Add NetworkPolicies to the gerrit-replica chart

By default, the network traffic to and from Kubernetes pods is not
restricted, which poses a potential security risk. The traffic can be
restricted using the NetworkPolicy resource of Kubernetes, which hadn't
been done so far for the gerrit-replica chart.

This change adds basic NetworkPolicies to the gerrit-replica chart:

- All traffic is blocked by default to and from pods installed by the
  chart.
- Egress to DNS services is allowed. The required ports can be
  configured in the chart.
- External ingress traffic is allowed to port 8080 of the gerrit-replica
  pods
- Custom ingress- and egress-rules can be configured for the
  gerrit-replica and git-backend pods to adjust for setups that are not
  fully supported by the basic NetworkPolicies.
- By default, the ingress traffic to the git-backend is unrestricted.
  This is implemented as a custom rule in the chart's values.yaml file
  and should be further restricted.
  Leaving it unrestricted provides better initial compatibility.
- If istio is used, traffic between the istio ingressgateway and the
  pods of the gerrit-replica chart is allowed.

Using the NetworkPolicies of the chart is optional and disabled by
default to reduce the initial complexity.

Change-Id: I4d12d8e259b8f8c53785d3f9ce321eb04b92c439
diff --git a/helm-charts/gerrit-replica/README.md b/helm-charts/gerrit-replica/README.md
index 246ddce..e93b2af 100644
--- a/helm-charts/gerrit-replica/README.md
+++ b/helm-charts/gerrit-replica/README.md
@@ -138,6 +138,54 @@
 | `nfsWorkaround.idDomain` | The ID-domain that should be used to map user-/group-IDs for the NFS mount | `localdomain.com` |
 
 
+### Network policies
+
+| Parameter                  | Description                                      | Default      |
+|----------------------------|--------------------------------------------------|--------------|
+| `networkPolicies.enabled`  | Whether to enable preconfigured NetworkPolicies  | `false`      |
+| `networkPolicies.dnsPorts` | List of ports used by DNS-service (e.g. KubeDNS) | `[53, 8053]` |
+
+The NetworkPolicies provided here are quite strict and do not account for all
+possible scenarios. Thus, custom NetworkPolicies have to be added, e.g. for
+connecting to a database. On the other hand some defaults may be not restrictive
+enough. By default, the ingress traffic of the git-backend pod is not restricted.
+Thus, every source (with the right credentials) could push to the git-backend.
+To add an additional layer of security, the ingress rule could be defined more
+finegrained. The chart provides the possibility to define custom rules for ingress-
+traffic of the git-backend pod under `gitBackend.networkPolicy.ingress`.
+Depending on the scenario, there are different ways to restrict the incoming
+connections.
+
+If the replicator (e.g. Gerrit) is running in a pod on the same cluster,
+a podSelector (and namespaceSelector, if the pod is running in a different
+namespace) can be used to whitelist the traffic:
+
+```yaml
+gitBackend:
+  networkPolicy:
+    ingress:
+    - from:
+      - podSelector:
+          matchLabels:
+            app: gerrit
+```
+
+If the replicator is outside the cluster, the IP of the replicator can also be
+whitelisted, e.g.:
+
+```yaml
+gitBackend:
+  networkPolicy:
+    ingress:
+    - from:
+      - ipBlock:
+          cidr: xxx.xxx.0.0/16
+```
+
+The same principle also applies to other use cases, e.g. connecting to a database.
+For more information about the NetworkPolicy resource refer to the
+[Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/network-policies/).
+
 ### Storage for Git repositories
 
 | Parameter                               | Description                                     | Default                |
@@ -220,6 +268,8 @@
 | `gitBackend.replicas`                      | Number of pod replicas to deploy                                                   | `1`                                                                       |
 | `gitBackend.maxSurge`                      | Max. percentage or number of pods allowed to be scheduled above the desired number | `25%`                                                                     |
 | `gitBackend.maxUnavailable`                | Max. percentage or number of pods allowed to be unavailable at a time              | `100%`                                                                    |
+| `gitBackend.networkPolicy.ingress`         | Custom ingress-network policy for git-backend pods                                 | `[{}]` (allow all)                                                        |
+| `gitBackend.networkPolicy.egress`          | Custom egress-network policy for git-backend pods                                  | `nil`                                                                     |
 | `gitBackend.resources`                     | Configure the amount of resources the pod requests/is allowed                      | `requests.cpu: 100m`                                                      |
 |                                            |                                                                                    | `requests.memory: 256Mi`                                                  |
 |                                            |                                                                                    | `limits.cpu: 100m`                                                        |
@@ -285,6 +335,8 @@
 |                                               |                                                                                                     | `requests.memory: 5Gi`                                                          |
 |                                               |                                                                                                     | `limits.cpu: 1`                                                                 |
 |                                               |                                                                                                     | `limits.memory: 6Gi`                                                            |
+| `gerritReplica.networkPolicy.ingress`         | Custom ingress-network policy for gerrit-replica pods                                               | `nil`                                                                           |
+| `gerritReplica.networkPolicy.egress`          | Custom egress-network policy for gerrit-replica pods                                                | `nil`                                                                           |
 | `gerritReplica.service.type`                  | Which kind of Service to deploy                                                                     | `NodePort`                                                                      |
 | `gerritReplica.service.http.port`             | Port over which to expose HTTP                                                                      | `80`                                                                            |
 | `gerritReplica.service.ssh.enabled`           | Whether to enable SSH for the Gerrit replica                                                        | `false`                                                                         |
diff --git a/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml b/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
index 3cf609b..a3a2242 100644
--- a/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
+++ b/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
@@ -13,11 +13,16 @@
   jobTemplate:
     spec:
       template:
-        {{ if .Values.istio.enabled -}}
         metadata:
+          {{ if .Values.istio.enabled -}}
           annotations:
             sidecar.istio.io/inject: "false"
-        {{- end }}
+          {{- end }}
+          labels:
+            app: git-gc
+            chart: {{ template "gerrit-replica.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
         spec:
           restartPolicy: OnFailure
           securityContext:
diff --git a/helm-charts/gerrit-replica/templates/netpol.yaml b/helm-charts/gerrit-replica/templates/netpol.yaml
new file mode 100644
index 0000000..9e8818f
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/netpol.yaml
@@ -0,0 +1,211 @@
+{{ if .Values.networkPolicies.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-default-deny-all
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Ingress
+  - Egress
+  ingress: []
+  egress: []
+---
+{{ if .Values.networkPolicies.dnsPorts -}}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ .Release.Name }}-allow-dns-access
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Egress
+  egress:
+  - ports:
+    {{ range .Values.networkPolicies.dnsPorts -}}
+    - port: {{ . }}
+      protocol: UDP
+    - port: {{ . }}
+      protocol: TCP
+    {{ end }}
+{{- end }}
+---
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-allow-external
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit-replica
+  ingress:
+  - ports:
+    - port: 8080
+    from: []
+---
+{{ if or .Values.gitBackend.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: git-backend-custom-ingress-policies
+  labels:
+    app: git-backend
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app: git-backend
+  ingress:
+{{ toYaml .Values.gitBackend.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gitBackend.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: git-backend-custom-egress-policies
+  labels:
+    app: git-backend
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app: git-backend
+  egress:
+{{ toYaml .Values.gitBackend.networkPolicy.egress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerritReplica.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-custom-ingress-policies
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit-replica
+  ingress:
+{{ toYaml .Values.gerritReplica.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerritReplica.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-custom-egress-policies
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit-replica
+  egress:
+{{ toYaml .Values.gerritReplica.networkPolicy.egress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.istio.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: istio-proxy
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Egress
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  egress:
+  - ports:
+    - protocol: TCP
+      port: 15012
+  ingress:
+  - ports:
+    - protocol: TCP
+      port: 15012
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ .Release.Name }}-istio-ingress
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  ingress:
+  - ports:
+    - protocol: TCP
+      port: 80
+    {{ if .Values.istio.ssh.enabled }}
+    - protocol: TCP
+      port: {{ .Values.gerritReplica.service.ssh.port }}
+    {{- end }}
+    from:
+    - namespaceSelector:
+        matchLabels:
+          name: istio-system
+    - podSelector:
+        matchLabels:
+          istio: ingressgateway
+
+{{- end }}
+{{- end }}
diff --git a/helm-charts/gerrit-replica/values.yaml b/helm-charts/gerrit-replica/values.yaml
index d2df1e0..46188bd 100644
--- a/helm-charts/gerrit-replica/values.yaml
+++ b/helm-charts/gerrit-replica/values.yaml
@@ -46,6 +46,13 @@
   idDomain: localdomain.com
 
 
+networkPolicies:
+  enabled: false
+  dnsPorts:
+  - 53
+  - 8053
+
+
 gitRepositoryStorage:
   externalPVC:
     use: false
@@ -120,6 +127,16 @@
   # work.
   maxUnavailable: 100%
 
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups. Here custom rules may be added to whitelist some additional
+  # connections.
+  networkPolicy:
+    # This allows ingress traffic from all sources. If possible, this should be
+    # limited to the respective primary Gerrit that replicates to this replica.
+    ingress:
+    - {}
+    egress: []
+
   resources:
     requests:
       cpu: 100m
@@ -230,6 +247,13 @@
       cpu: 1
       memory: 6Gi
 
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups, e.g. when trying to connect to an external database. Here
+  # custom rules may be added to whitelist some additional connections.
+  networkPolicy:
+    ingress: []
+    egress: []
+
   service:
     type: NodePort
     http: