From 90dabe31ed9ffeb72f75816c4b9d5c4ccf0c3c59 Mon Sep 17 00:00:00 2001 From: mikaeld Date: Mon, 17 Jul 2023 17:59:16 -0400 Subject: [PATCH 1/2] feat(chart): Add pod security context to pgbouncer. --- .../pgbouncer/pgbouncer-deployment.yaml | 8 ++--- chart/values.schema.json | 16 ++++++++- chart/values.yaml | 1 + helm_tests/security/test_security_context.py | 33 ++++++++++++++----- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/chart/templates/pgbouncer/pgbouncer-deployment.yaml b/chart/templates/pgbouncer/pgbouncer-deployment.yaml index fde07807c4e63..14665692fcf61 100644 --- a/chart/templates/pgbouncer/pgbouncer-deployment.yaml +++ b/chart/templates/pgbouncer/pgbouncer-deployment.yaml @@ -26,8 +26,9 @@ {{- $tolerations := or .Values.pgbouncer.tolerations .Values.tolerations }} {{- $topologySpreadConstraints := or .Values.pgbouncer.topologySpreadConstraints .Values.topologySpreadConstraints }} {{- $revisionHistoryLimit := or .Values.pgbouncer.revisionHistoryLimit .Values.revisionHistoryLimit }} -{{- $containerSecurityContext := include "containerSecurityContext" (list . .Values.pgbouncer) }} -{{- $containerSecurityContextMetricsExporter := include "containerSecurityContext" (list . .Values.pgbouncer.metricsExporterSidecar) }} +{{- $securityContext := include "localPodSecurityContext" .Values.pgbouncer }} +{{- $containerSecurityContext := include "externalContainerSecurityContext" .Values.pgbouncer }} +{{- $containerSecurityContextMetricsExporter := include "externalContainerSecurityContext" .Values.pgbouncer.metricsExporterSidecar }} apiVersion: apps/v1 kind: Deployment metadata: @@ -82,8 +83,7 @@ spec: tolerations: {{- toYaml $tolerations | nindent 8 }} topologySpreadConstraints: {{- toYaml $topologySpreadConstraints | nindent 8 }} serviceAccountName: {{ include "pgbouncer.serviceAccountName" . }} - securityContext: - runAsUser: {{ .Values.pgbouncer.uid }} + securityContext: {{ $securityContext | nindent 8 }} restartPolicy: Always {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: diff --git a/chart/values.schema.json b/chart/values.schema.json index a4a329321a2f1..ce116a2ea77a4 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -5080,10 +5080,24 @@ "$ref": "#/definitions/io.k8s.api.core.v1.ResourceRequirements" }, "securityContexts": { - "description": "Security context definition for the PgBouncer. If not set, the values from global `securityContexts` will be used.", + "description": "Security context definition for the PgBouncer.", "type": "object", "x-docsSection": "Kubernetes", "properties": { + "pod": { + "description": "Pod security context definition for the PgBouncer.", + "type": "object", + "$ref": "#/definitions/io.k8s.api.core.v1.PodSecurityContext", + "default": {}, + "x-docsSection": "Kubernetes", + "examples": [ + { + "runAsUser": 65534, + "runAsGroup": 0, + "fsGroup": 0 + } + ] + }, "container": { "description": "Container security context definition for the PgBouncer.", "type": "object", diff --git a/chart/values.yaml b/chart/values.yaml index 53d9630007971..9569ec2d82f79 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -1833,6 +1833,7 @@ pgbouncer: # Detailed default security context for pgbouncer for container level securityContexts: + pod: {} container: {} metricsExporterSidecar: diff --git a/helm_tests/security/test_security_context.py b/helm_tests/security/test_security_context.py index f7693af198053..25b14c41bc1ad 100644 --- a/helm_tests/security/test_security_context.py +++ b/helm_tests/security/test_security_context.py @@ -57,6 +57,14 @@ def test_check_statsd_uid(self): assert 3000 == jmespath.search("spec.template.spec.securityContext.runAsUser", docs[0]) + def test_check_pgbouncer_uid(self): + docs = render_chart( + values={"pgbouncer": {"enabled": True, "uid": 3000}}, + show_only=["templates/pgbouncer/pgbouncer-deployment.yaml"], + ) + + assert 3000 == jmespath.search("spec.template.spec.securityContext.runAsUser", docs[0]) + def test_check_cleanup_job(self): docs = render_chart( values={"uid": 3000, "gid": 30, "cleanup": {"enabled": True}}, @@ -219,7 +227,10 @@ def test_global_security_context(self): ctx_value_pod = {"runAsUser": 7000} ctx_value_container = {"allowPrivilegeEscalation": False} docs = render_chart( - values={"securityContexts": {"containers": ctx_value_container, "pod": ctx_value_pod}}, + values={ + "securityContexts": {"containers": ctx_value_container, "pod": ctx_value_pod}, + "pgbouncer": {"enabled": True}, + }, show_only=[ "templates/flower/flower-deployment.yaml", "templates/scheduler/scheduler-deployment.yaml", @@ -228,31 +239,35 @@ def test_global_security_context(self): "templates/jobs/create-user-job.yaml", "templates/jobs/migrate-database-job.yaml", "templates/triggerer/triggerer-deployment.yaml", + "templates/pgbouncer/pgbouncer-deployment.yaml", "templates/statsd/statsd-deployment.yaml", "templates/redis/redis-statefulset.yaml", ], ) - - for index in range(len(docs) - 2): + for index in range(len(docs) - 3): assert ctx_value_container == jmespath.search( "spec.template.spec.containers[0].securityContext", docs[index] ) assert ctx_value_pod == jmespath.search("spec.template.spec.securityContext", docs[index]) - # Global security context is not propagated to redis and statsd, so we test default value + # Global security context is not propagated to pgbouncer, redis and statsd, so we test default value default_ctx_value_container = {"allowPrivilegeEscalation": False, "capabilities": {"drop": ["ALL"]}} + default_ctx_value_pod_pgbouncer = {"runAsUser": 65534} default_ctx_value_pod_statsd = {"runAsUser": 65534} default_ctx_value_pod_redis = {"runAsUser": 0} - for index in range(len(docs) - 2, len(docs)): + for index in range(len(docs) - 3, len(docs)): assert default_ctx_value_container == jmespath.search( "spec.template.spec.containers[0].securityContext", docs[index] ) - assert default_ctx_value_pod_statsd == jmespath.search( - "spec.template.spec.securityContext", docs[len(docs) - 2] + # Test pgbouncer metrics-exporter container + assert default_ctx_value_container == jmespath.search( + "spec.template.spec.containers[1].securityContext", docs[-3] ) - assert default_ctx_value_pod_redis == jmespath.search( - "spec.template.spec.securityContext", docs[len(docs) - 1] + assert default_ctx_value_pod_pgbouncer == jmespath.search( + "spec.template.spec.securityContext", docs[-3] ) + assert default_ctx_value_pod_statsd == jmespath.search("spec.template.spec.securityContext", docs[-2]) + assert default_ctx_value_pod_redis == jmespath.search("spec.template.spec.securityContext", docs[-1]) # Test securityContexts for main containers def test_main_container_setting(self): From 30b2b4a8ee53bd7ee1aa817edcd365c9aa83e7df Mon Sep 17 00:00:00 2001 From: mikaeld Date: Tue, 18 Jul 2023 10:52:22 -0400 Subject: [PATCH 2/2] refactor test_global_security_context with pythonic loops --- helm_tests/security/test_security_context.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helm_tests/security/test_security_context.py b/helm_tests/security/test_security_context.py index 25b14c41bc1ad..72fba4a4fbe81 100644 --- a/helm_tests/security/test_security_context.py +++ b/helm_tests/security/test_security_context.py @@ -244,20 +244,20 @@ def test_global_security_context(self): "templates/redis/redis-statefulset.yaml", ], ) - for index in range(len(docs) - 3): + for doc in docs[:-3]: assert ctx_value_container == jmespath.search( - "spec.template.spec.containers[0].securityContext", docs[index] + "spec.template.spec.containers[0].securityContext", doc ) - assert ctx_value_pod == jmespath.search("spec.template.spec.securityContext", docs[index]) + assert ctx_value_pod == jmespath.search("spec.template.spec.securityContext", doc) # Global security context is not propagated to pgbouncer, redis and statsd, so we test default value default_ctx_value_container = {"allowPrivilegeEscalation": False, "capabilities": {"drop": ["ALL"]}} default_ctx_value_pod_pgbouncer = {"runAsUser": 65534} default_ctx_value_pod_statsd = {"runAsUser": 65534} default_ctx_value_pod_redis = {"runAsUser": 0} - for index in range(len(docs) - 3, len(docs)): + for doc in docs[-3:]: assert default_ctx_value_container == jmespath.search( - "spec.template.spec.containers[0].securityContext", docs[index] + "spec.template.spec.containers[0].securityContext", doc ) # Test pgbouncer metrics-exporter container assert default_ctx_value_container == jmespath.search(