From bef0cea1b117d822f01d51b8fab5b9b1be841454 Mon Sep 17 00:00:00 2001 From: nmasse-itix Date: Sat, 18 Dec 2021 19:10:48 +0800 Subject: [PATCH] split the securityContext in two: pod and container securityContext (#259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello ! I'm using the new Helm chart (5.x) and I really like the new configuration mechanism. 👍 I would like to contribute the following enhancement. ## The problem I want to solve I'm trying to deploy Gitea in a Kubernetes shared platform and I need to make sure each instance is running as a different user so that in case of container escape, the risk of data leak is minimized. Additionally, on my platform (OpenShift), arbitrary users (such as uid 1000 for Gitea) are not allowed. The current helm chart does not allow me to achieve this because: - the container security context is configurable only for the main container. The security context of init containers cannot be specified. - a fixed uid is hard coded - a fixed fs group is hard coded Also, the securityContext of a pod and the securityContext of a container do not accept the same options. - https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#podsecuritycontext-v1-core - https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#securitycontext-v1-core ## How I'm solving the problem I split the `securityContext` (values.yaml) in two: `containerSecurityContext` and `podSecurityContext`. The containerSecurityContext applies to all containers (init and main) in order to be consistent with file permissions. The behavior for existing deployments is unchanged: - fsGroup 1000 is the default value for the podSecurityContext variable - the "configure-gitea" init container uses the uid 1000 unless otherwise stated in the containerSecurityContext - the main container is using the existing securityContext variable when defined in order not to break existing deployments and uses the new containerSecurityContext variable if not. This approach is well tested: it is used consistently on bitnami's Helm charts. ## How I tested I tested both root and rootless variants on a Kubernetes 1.22, as well as rootless variant on OpenShift 4.7. **rootless variant on Kubernetes**: ```yaml podSecurityContext: fsGroup: 10001 containerSecurityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL add: - SYS_CHROOT privileged: false runAsGroup: 10001 runAsNonRoot: true runAsUser: 10001 extraVolumes: - name: var-lib-gitea emptyDir: {} extraVolumeMounts: - name: var-lib-gitea readOnly: false mountPath: "/var/lib/gitea" ``` **rootless variant on OpenShift**: ```yaml podSecurityContext: fsGroup: null containerSecurityContext: allowPrivilegeEscalation: false privileged: false runAsNonRoot: true runAsUser: 1000790000 extraVolumes: - name: var-lib-gitea emptyDir: {} extraVolumeMounts: - name: var-lib-gitea readOnly: false mountPath: "/var/lib/gitea" ``` Let me know if something is unclear. Co-authored-by: Nicolas MASSE Reviewed-on: https://gitea.com/gitea/helm-chart/pulls/259 Reviewed-by: luhahn Reviewed-by: justusbunsi Co-authored-by: nmasse-itix Co-committed-by: nmasse-itix --- README.md | 3 ++- templates/gitea/statefulset.yaml | 20 +++++++++++++++++--- values.yaml | 12 ++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0fb82e7..a97bd84 100644 --- a/README.md +++ b/README.md @@ -580,7 +580,8 @@ gitea: | `extraVolumes` | Additional volumes to mount to the Gitea statefulset | `{}` | | `extraVolumeMounts` | Additional volume mounts for the Gitea containers | `{}` | | `initPreScript` | Bash script copied verbatim to start of init container | | -| `securityContext` | Run as a specific securityContext | `{}` | +| `podSecurityContext.fsGroup` | Set the shared file system group for all containers | 1000 | +| `containerSecurityContext` | Run init and gitea containers as a specific securityContext | `{}` | | `schedulerName` | Use an alternate scheduler, e.g. "stork" | | ### Image diff --git a/templates/gitea/statefulset.yaml b/templates/gitea/statefulset.yaml index 1d5aa18..734f342 100644 --- a/templates/gitea/statefulset.yaml +++ b/templates/gitea/statefulset.yaml @@ -38,7 +38,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} securityContext: - fsGroup: 1000 + {{- toYaml .Values.podSecurityContext | nindent 8 }} initContainers: - name: init-directories image: "{{ include "gitea.image" . }}" @@ -65,6 +65,8 @@ spec: {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} + securityContext: + {{- toYaml .Values.containerSecurityContext | nindent 12 }} - name: init-app-ini image: "{{ include "gitea.image" . }}" command: ["/usr/sbin/config_environment.sh"] @@ -90,11 +92,18 @@ spec: {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} + securityContext: + {{- toYaml .Values.containerSecurityContext | nindent 12 }} - name: configure-gitea image: "{{ include "gitea.image" . }}" command: ["/usr/sbin/configure_gitea.sh"] securityContext: - runAsUser: 1000 + {{- /* By default this container runs as user 1000 unless otherwise stated */ -}} + {{- $csc := deepCopy .Values.containerSecurityContext -}} + {{- if not (hasKey $csc "runAsUser") -}} + {{- $_ := set $csc "runAsUser" 1000 -}} + {{- end -}} + {{- toYaml $csc | nindent 12 }} env: - name: GITEA_APP_INI value: /data/gitea/conf/app.ini @@ -207,7 +216,12 @@ spec: resources: {{- toYaml .Values.resources | nindent 12 }} securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} + {{- /* Honor the deprecated securityContext variable when defined */ -}} + {{- if .Values.containerSecurityContext -}} + {{ toYaml .Values.containerSecurityContext | nindent 12 -}} + {{- else -}} + {{ toYaml .Values.securityContext | nindent 12 -}} + {{- end }} volumeMounts: - name: temp mountPath: /tmp diff --git a/values.yaml b/values.yaml index fabc055..ef6f324 100644 --- a/values.yaml +++ b/values.yaml @@ -14,8 +14,11 @@ image: imagePullSecrets: [] -# only usable with rootless image due to image design -securityContext: {} +# Security context is only usable with rootless image due to image design +podSecurityContext: + fsGroup: 1000 + +containerSecurityContext: {} # allowPrivilegeEscalation: false # capabilities: # drop: @@ -33,6 +36,11 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 +# DEPRECATED. The securityContext variable has been split two: +# - containerSecurityContext +# - podSecurityContext. +securityContext: {} + service: http: type: ClusterIP