diff --git a/elasticsearch/README.md b/elasticsearch/README.md index e89f8a87b..a0d3ddb91 100644 --- a/elasticsearch/README.md +++ b/elasticsearch/README.md @@ -114,6 +114,8 @@ helm install --name elasticsearch elastic/elasticsearch --set imageTag=7.3.0 | `masterTerminationFix` | A workaround needed for Elasticsearch < 7.2 to prevent master status being lost during restarts [#63](https://github.com/elastic/helm-charts/issues/63) | `false` | | `lifecycle` | Allows you to add lifecycle configuration. See [values.yaml](./values.yaml) for an example of the formatting. | `{}` | | `keystore` | Allows you map Kubernetes secrets into the keystore. See the [config example](/elasticsearch/examples/config/values.yaml) and [how to use the keystore](#how-to-use-the-keystore) | `[]` | +| `rbac` | Configuration for creating a role, role binding and service account as part of this helm chart with `create: true`. Also can be used to reference an external service account with `serviceAccountName: "externalServiceAccountName"`. | `create: false`
`serviceAccountName: ""` | +| `podSecurityPolicy` | Configuration for create a pod security policy with minimal permissions to run this Helm chart with `create: true`. Also can be used to reference an external pod security policy with `name: "externalPodSecurityPolicy"` | `create: false`
`name: ""` | ## Try it out diff --git a/elasticsearch/templates/podsecuritypolicy.yaml b/elasticsearch/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..1e65b2864 --- /dev/null +++ b/elasticsearch/templates/podsecuritypolicy.yaml @@ -0,0 +1,14 @@ +{{- if .Values.podSecurityPolicy.create -}} +{{- $fullName := include "uname" . -}} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ default $fullName .Values.podSecurityPolicy.name | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +spec: +{{ toYaml .Values.podSecurityPolicy.spec | indent 2 }} +{{- end -}} diff --git a/elasticsearch/templates/role.yaml b/elasticsearch/templates/role.yaml new file mode 100644 index 000000000..d616e80d3 --- /dev/null +++ b/elasticsearch/templates/role.yaml @@ -0,0 +1,25 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "uname" . -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $fullName | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + {{- if eq .Values.podSecurityPolicy.name "" }} + - {{ $fullName | quote }} + {{- else }} + - {{ .Values.podSecurityPolicy.name | quote }} + {{- end }} + verbs: + - use +{{- end -}} diff --git a/elasticsearch/templates/rolebinding.yaml b/elasticsearch/templates/rolebinding.yaml new file mode 100644 index 000000000..c2b6070a4 --- /dev/null +++ b/elasticsearch/templates/rolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "uname" . -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $fullName | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +subjects: + - kind: ServiceAccount + {{- if eq .Values.rbac.serviceAccountName "" }} + name: {{ $fullName | quote }} + {{- else }} + name: {{ .Values.rbac.serviceAccountName | quote }} + {{- end }} + namespace: {{ .Release.Namespace | quote }} +roleRef: + kind: Role + name: {{ $fullName | quote }} + apiGroup: rbac.authorization.k8s.io +{{- end -}} diff --git a/elasticsearch/templates/serviceaccount.yaml b/elasticsearch/templates/serviceaccount.yaml new file mode 100644 index 000000000..59bbd5326 --- /dev/null +++ b/elasticsearch/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "uname" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if eq .Values.rbac.serviceAccountName "" }} + name: {{ $fullName | quote }} + {{- else }} + name: {{ .Values.rbac.serviceAccountName | quote }} + {{- end }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +{{- end -}} diff --git a/elasticsearch/templates/statefulset.yaml b/elasticsearch/templates/statefulset.yaml index 5a545a0cb..2af675e61 100644 --- a/elasticsearch/templates/statefulset.yaml +++ b/elasticsearch/templates/statefulset.yaml @@ -58,6 +58,11 @@ spec: {{- if .Values.fsGroup }} fsGroup: {{ .Values.fsGroup }} # Deprecated value, please use .Values.podSecurityContext.fsGroup {{- end }} + {{- if .Values.rbac.create }} + serviceAccountName: "{{ template "uname" . }}" + {{- else if not (eq .Values.rbac.serviceAccountName "") }} + serviceAccountName: {{ .Values.rbac.serviceAccountName | quote }} + {{- end }} {{- with .Values.tolerations }} tolerations: {{ toYaml . | indent 6 }} diff --git a/elasticsearch/tests/elasticsearch_test.py b/elasticsearch/tests/elasticsearch_test.py index a4949eef9..c194c6a6b 100755 --- a/elasticsearch/tests/elasticsearch_test.py +++ b/elasticsearch/tests/elasticsearch_test.py @@ -899,3 +899,70 @@ def test_keystore_volumes(): }] } } in s['volumes'] +def test_pod_security_policy(): + ## Make sure the default config is not creating any resources + config = '' + resources = ('role', 'rolebinding', 'serviceaccount', 'podsecuritypolicy') + r = helm_template(config) + for resource in resources: + assert resource not in r + assert 'serviceAccountName' not in r['statefulset'][uname]['spec']['template']['spec'] + + ## Make sure all the resources are created with default values + config = ''' +rbac: + create: true + serviceAccountName: "" + +podSecurityPolicy: + create: true + name: "" +''' + r = helm_template(config) + for resource in resources: + assert resource in r + assert r['role'][uname]['rules'][0] == {"apiGroups": ["extensions"], "verbs": ["use"], "resources": ["podsecuritypolicies"], "resourceNames": [uname]} + assert r['rolebinding'][uname]['subjects'] == [{"kind": "ServiceAccount", "namespace": "default", "name": uname}] + assert r['rolebinding'][uname]['roleRef'] == {"apiGroup": "rbac.authorization.k8s.io", "kind": "Role", "name": uname} + assert r['statefulset'][uname]['spec']['template']['spec']['serviceAccountName'] == uname + psp_spec = r['podsecuritypolicy'][uname]['spec'] + assert psp_spec['privileged'] is True + + +def test_external_pod_security_policy(): + ## Make sure we can use an externally defined pod security policy + config = ''' +rbac: + create: true + serviceAccountName: "" + +podSecurityPolicy: + create: false + name: "customPodSecurityPolicy" +''' + resources = ('role', 'rolebinding') + r = helm_template(config) + for resource in resources: + assert resource in r + + assert r['role'][uname]['rules'][0] == {"apiGroups": ["extensions"], "verbs": ["use"], "resources": ["podsecuritypolicies"], "resourceNames": ["customPodSecurityPolicy"]} + + +def test_external_service_account(): + ## Make sure we can use an externally defined service account + config = ''' +rbac: + create: false + serviceAccountName: "customServiceAccountName" + +podSecurityPolicy: + create: false + name: "" +''' + resources = ('role', 'rolebinding', 'serviceaccount') + r = helm_template(config) + + assert r['statefulset'][uname]['spec']['template']['spec']['serviceAccountName'] == "customServiceAccountName" + # When referencing an external service account we do not want any resources to be created. + for resource in resources: + assert resource not in r diff --git a/elasticsearch/values.yaml b/elasticsearch/values.yaml index 78f208849..575f2ce63 100755 --- a/elasticsearch/values.yaml +++ b/elasticsearch/values.yaml @@ -86,6 +86,28 @@ volumeClaimTemplate: requests: storage: 30Gi +rbac: + create: false + serviceAccountName: "" + +podSecurityPolicy: + create: false + name: "" + spec: + privileged: true + fsGroup: + rule: RunAsAny + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - secret + - configMap + - persistentVolumeClaim + persistence: enabled: true annotations: {}