Add NetworkPolicies to the gerrit 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 chart.

This change adds basic NetworkPolicies to the gerrit 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
  pods
- Custom ingress- and egress-rules can be configured for the
  gerrit pods to adjust for setups that are not fully supported
  by the basic NetworkPolicies.

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

Change-Id: Idb9b11f7592233595e990919fae468143613663a
diff --git a/helm-charts/gerrit/README.md b/helm-charts/gerrit/README.md
index 8220917..b4c40a6 100644
--- a/helm-charts/gerrit/README.md
+++ b/helm-charts/gerrit/README.md
@@ -104,6 +104,62 @@
 | `storageClasses.shared.reclaimPolicy`  | Whether to `Retain` or `Delete` volumes, when they become unbound | `Delete`                                          |
 | `storageClasses.shared.parameters`     | Parameters for the provisioner                                    | `parameters.mountOptions: vers=4.1`               |
 
+### 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
+allowing Gerrit to replicate to a Gerrit replica. By default, the egress traffic
+of the gerrit pod is blocked, except for connections to the DNS-server.
+Thus, replication which requires Gerrit to perform git pushes to the replica will
+not work. The chart provides the possibility to define custom rules for egress-
+traffic of the gerrit pod under `gerrit.networkPolicy.egress`.
+Depending on the scenario, there are different ways to allow the required
+connections. The easiest way is to allow all egress-traffic for the gerrit
+pods:
+
+```yaml
+gerrit:
+  networkPolicy:
+    egress:
+    - {}
+```
+
+If the remote that is replicated to is running in a pod on the same cluster and
+the service-DNS is used as the remote's URL (e.g. http://gerrit-replica-git-backend-service:80/git/${name}.git),
+a podSelector (and namespaceSelector, if the pod is running in a different
+namespace) can be used to whitelist the traffic:
+
+```yaml
+gerrit:
+  networkPolicy:
+    egress:
+    - to:
+      - podSelector:
+          matchLabels:
+            app: git-backend
+```
+
+If the remote is outside the cluster, the IP of the remote or its load balancer
+can also be whitelisted, e.g.:
+
+```yaml
+gerrit:
+  networkPolicy:
+    egress:
+    - to:
+      - 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                |
@@ -160,6 +216,8 @@
 | `gerrit.persistence.size`              | Storage size for persisted Gerrit site                                                              | `10Gi`                                                                                   |
 | `gerrit.livenessProbe`                 | Configuration of the liveness probe timings                                                         | `{initialDelaySeconds: 30, periodSeconds: 5}`                                            |
 | `gerrit.readinessProbe`                | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 5, periodSeconds: 1}`                                             |
+| `gerrit.networkPolicy.ingress`         | Custom ingress-network policy for gerrit pods                                                       | `nil`                                                                                    |
+| `gerrit.networkPolicy.egress`          | Custom egress-network policy for gerrit pods                                                        | `nil`                                                                                    |
 | `gerrit.service.type`                  | Which kind of Service to deploy                                                                     | `NodePort`                                                                               |
 | `gerrit.service.http.port`             | Port over which to expose HTTP                                                                      | `80`                                                                                     |
 | `gerrit.ingress.host`                  | REQUIRED: Host name to use for the Ingress (required for Ingress)                                   | `nil`                                                                                    |
diff --git a/helm-charts/gerrit/templates/git-gc.cronjob.yaml b/helm-charts/gerrit/templates/git-gc.cronjob.yaml
index fa5292c..df23479 100644
--- a/helm-charts/gerrit/templates/git-gc.cronjob.yaml
+++ b/helm-charts/gerrit/templates/git-gc.cronjob.yaml
@@ -13,6 +13,12 @@
   jobTemplate:
     spec:
       template:
+        metadata:
+          labels:
+            app: git-gc
+            chart: {{ template "gerrit.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
         spec:
           restartPolicy: OnFailure
           securityContext:
diff --git a/helm-charts/gerrit/templates/netpol.yaml b/helm-charts/gerrit/templates/netpol.yaml
new file mode 100644
index 0000000..76b0ab6
--- /dev/null
+++ b/helm-charts/gerrit/templates/netpol.yaml
@@ -0,0 +1,110 @@
+{{ if .Values.networkPolicies.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-default-deny-all
+  labels:
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.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.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.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-allow-external
+  labels:
+    app: gerrit
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit
+  ingress:
+  - ports:
+    - port: 8080
+    from: []
+---
+{{ if or .Values.gerrit.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-custom-ingress-policies
+  labels:
+    app: gerrit
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit
+  ingress:
+{{ toYaml .Values.gerrit.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerrit.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-custom-egress-policies
+  labels:
+    app: gerrit
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app: gerrit
+  egress:
+{{ toYaml .Values.gerrit.networkPolicy.egress | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/helm-charts/gerrit/values.yaml b/helm-charts/gerrit/values.yaml
index c9add68..2d196ab 100644
--- a/helm-charts/gerrit/values.yaml
+++ b/helm-charts/gerrit/values.yaml
@@ -42,6 +42,13 @@
       mountOptions: vers=4.1
 
 
+networkPolicies:
+  enabled: false
+  dnsPorts:
+  - 53
+  - 8053
+
+
 gitRepositoryStorage:
   externalPVC:
     use: false
@@ -97,6 +104,22 @@
     initialDelaySeconds: 5
     periodSeconds: 1
 
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups, e.g. when trying to replicate to a Gerrit replica. Here
+  # custom rules may be added to whitelist some additional connections.
+  networkPolicy:
+    ingress: []
+    egress: []
+    # An example for an egress rule to allow replication to a Gerrit replica
+    # installed with the gerrit-replica setup in the same cluster and namespace
+    # by using the service as the replication destination
+    # (e.g. http://gerrit-replica-git-backend-service:80/git/${name}.git):
+    #
+    # - to:
+    #   - podSelector:
+    #       matchLabels:
+    #         app: git-backend
+
   service:
     type: NodePort
     http: