ERROR

Helm Chart Security Audit Fail: Fixing Missing PodSecurityContext for Compliance

Quick Fix Summary

TL;DR

Add a `securityContext` block to your Pod spec and redeploy.

Security audits and Pod Security Standards (PSS) require a `securityContext` to be defined for Pods to enforce baseline security controls like non-root users and read-only root filesystems.

Diagnosis & Causes

  • Helm chart templates omit `securityContext` for flexibility.
  • Legacy charts not updated for modern security policies like PSS/PSA.
  • Recovery Steps

    1

    Step 1: Verify the Missing Context in Deployed Pods

    Identify which workloads are missing the PodSecurityContext by inspecting live Pod specs.

    bash
    kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{": "}{.spec.securityContext}{"\n"}{end}' | grep -v -E 'fsGroup|runAsGroup|runAsNonRoot|seccompProfile'
    kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A 10 '^spec:'
    2

    Step 2: Inspect the Helm Chart Templates

    Examine the chart's deployment template to locate where the Pod spec is defined and lacks securityContext.

    bash
    helm template <release-name> <chart-path> --dry-run | grep -A 20 -B 5 'kind: Deployment'
    cat <chart-path>/templates/deployment.yaml
    3

    Step 3: Define a Baseline PodSecurityContext in values.yaml

    Add a default security context configuration in your chart's values file. This is the recommended approach for configurable charts.

    yaml
    # Add to your values.yaml
    podSecurityContext:
      runAsNonRoot: true
      seccompProfile:
        type: RuntimeDefault
      runAsUser: 1000
      fsGroup: 2000
    4

    Step 4: Modify the Deployment Template to Use the Context

    Update the deployment.yaml template to inject the `podSecurityContext` from values into the Pod spec.

    yaml
    # In templates/deployment.yaml, within the Pod spec template
    spec:
      securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
      ...
    5

    Step 5: Apply a Test Upgrade in Dry-Run Mode

    Simulate the Helm upgrade to verify the changes render correctly without deploying.

    bash
    helm upgrade <release-name> <chart-path> --dry-run --debug --values ./values.yaml
    6

    Step 6: Perform the Helm Upgrade

    Deploy the fixed chart to your cluster.

    bash
    helm upgrade <release-name> <chart-path> --values ./values.yaml --namespace <namespace>
    7

    Step 7: Validate the Applied Security Context

    Confirm the new Pods are created with the correct securityContext.

    bash
    kubectl get pod -l app.kubernetes.io/instance=<release-name> -o jsonpath='{.items[*].spec.securityContext}'
    kubectl describe pod <new-pod-name> | grep -A 5 Security

    Architect's Pro Tip

    "If `runAsNonRoot: true` causes pods to crash, check the Dockerfile. The image may be configured to run as root (USER 0) or may not have a valid non-root user defined. Use `kubectl describe pod` to see the 'container has runAsNonRoot and image will run as root' error."

    Frequently Asked Questions

    Can I just add `securityContext` directly to the template without using values.yaml?

    Yes, but it reduces configurability and is not best practice for shareable charts. For a quick internal fix, you can hardcode it in the deployment.yaml template.

    My Pod fails with "container has runAsNonRoot and image will run as root". What now?

    You must either: 1) Modify the application's Dockerfile to define and use a non-root user (e.g., `USER 1000`), or 2) If the container genuinely requires root, configure your Pod Security Admission (PSA) controller with an exemption or use a less restrictive Pod Security Standard (e.g., 'privileged' baseline).

    Related Kubernetes Guides