> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Minimize The Admission Of Privileged Containers

### More Info:

Privileged containers have effectively unrestricted host access and can compromise the node. Block their admission in workload namespaces.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify workload namespaces and existing privileged pods**\
           Run on: any machine with kubectl access
           ```bash theme={null}
           # List namespaces (exclude obvious system ones; adjust as needed)
           kubectl get ns

           # List current privileged containers (for awareness)
           kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | \
           while read -r pod_name pod_namespace; do
             kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | \
             while read -r container; do
               container_name=$(echo "${container}" | jq -r '.name')
               container_privileged=$(echo "${container}" | jq -r '.securityContext.privileged' | sed -e 's/null/notset/g')
               if [ "${container_privileged}" = "true" ]; then
                 echo "NON-COMPLIANT pod=${pod_name} ns=${pod_namespace} container=${container_name}"
               fi
             done
           done
           ```

        2. **Decide namespace policy scope and exceptions**\
           Run on: administrator’s workstation (planning)
           * For each workload namespace, decide whether **all** privileged containers must be denied, or whether specific service accounts/namespaces need an exception (for example, infrastructure tooling).
           * For any allowed exceptions, plan separate namespaces or dedicated service accounts with clearly documented justification, since this control is MANUAL and risk-based.

        3. **Create a baseline policy to deny privileged containers in a namespace**\
           Run on: any machine with kubectl access\
           Example using the built-in `PodSecurity` admission (Kubernetes ≥1.25). Replace `<NAMESPACE>` with an actual workload namespace and repeat for each one where privileged containers must be blocked.
           ```bash theme={null}
           kubectl label namespace <NAMESPACE> \
             pod-security.kubernetes.io/enforce=restricted \
             pod-security.kubernetes.io/enforce-version=latest \
             pod-security.kubernetes.io/warn=restricted \
             pod-security.kubernetes.io/warn-version=latest \
             pod-security.kubernetes.io/audit=restricted \
             pod-security.kubernetes.io/audit-version=latest --overwrite
           ```
           This label set enforces the “restricted” Pod Security level, which disallows privileged containers (`securityContext.privileged: true`) in that namespace.

        4. **(If PodSecurity admission is not available) Apply a restrictive admission policy**\
           Run on: any machine with kubectl access\
           If your cluster uses a policy engine (for example, Kubernetes-native PodSecurityPolicies on legacy clusters, or Gatekeeper/Kyverno), implement or tighten the admission policy for each workload namespace so that containers with `.securityContext.privileged: true` are rejected. Example Kyverno ClusterPolicy (adjust names/namespaces to your environment before applying):
           ```bash theme={null}
           cat << 'EOF' > deny-privileged-containers.yaml
           apiVersion: kyverno.io/v1
           kind: ClusterPolicy
           metadata:
             name: deny-privileged-containers
           spec:
             validationFailureAction: enforce
             background: true
             rules:
               - name: disallow-privileged
                 match:
                   any:
                     - resources:
                         kinds:
                           - Pod
                         namespaces:
                           - "<NAMESPACE1>"
                           - "<NAMESPACE2>"
                 validate:
                   message: "Privileged containers are not allowed."
                   pattern:
                     spec:
                       containers:
                         - name: "*"
                           =(securityContext):
                             =(privileged): "false"
           EOF

           kubectl apply -f deny-privileged-containers.yaml
           ```
           Review this policy with your security team before applying, and tailor namespace lists and any needed exceptions.

        5. **Refactor or remove existing privileged workloads**\
           Run on: any machine with kubectl access\
           For each privileged pod identified in step 1 in user/workload namespaces:
           * Retrieve and edit the manifest:
             ```bash theme={null}
             kubectl get pod <POD_NAME> -n <NAMESPACE> -o yaml > /tmp/<POD_NAME>.yaml
             ```
           * In `/tmp/<POD_NAME>.yaml`, remove `securityContext.privileged: true` from each container, or set it to `false`, and adjust capabilities/host access to meet functional needs without privilege.
           * Recreate the workload (ideally via its Deployment/DaemonSet/Job manifests rather than directly from a Pod):
             ```bash theme={null}
             # If the pod is managed by a controller, edit the controller instead
             kubectl edit deployment <DEPLOYMENT_NAME> -n <NAMESPACE>
             # or apply the corrected manifest
             kubectl apply -f /tmp/<WORKLOAD>.yaml
             ```
           * Where privileged access is truly required and accepted, move such workloads into a clearly designated, tightly controlled namespace and exempt it deliberately from the restrictive policy, with documented approval.

        6. **Verify that privileged containers are no longer admitted**\
           Run on: any machine with kubectl access
           * Attempt to create a test privileged pod in a protected workload namespace; it should be rejected:
             ```bash theme={null}
             cat << 'EOF' | kubectl apply -n <NAMESPACE> -f -
             apiVersion: v1
             kind: Pod
             metadata:
               name: test-privileged
             spec:
               containers:
                 - name: test
                   image: busybox
                   command: ["sh", "-c", "sleep 3600"]
                   securityContext:
                     privileged: true
             EOF
             ```
           * Confirm that any remaining running containers with `privileged: true` are only in explicitly approved namespaces (if any) and that user/workload namespaces are clean:
             ```bash theme={null}
             kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | \
             while read -r pod_name pod_namespace; do
               kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | \
               while read -r container; do
                 container_name=$(echo "${container}" | jq -r '.name')
                 container_privileged=$(echo "${container}" | jq -r '.securityContext.privileged' | sed -e 's/null/notset/g')
                 if [ "${container_privileged}" = "true" ]; then
                   echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_privileged: ${container_privileged} is_compliant: false"
                 fi
               done
             done
             ```
           Ensure that no lines with `is_compliant: false` appear for regular workload namespaces.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Create a PodSecurity admission label set that forbids privileged containers
        # Run on: any machine with kubectl access

        # Example: apply to one user workload namespace (replace "my-workload-namespace" with the real name)
        kubectl label namespace my-workload-namespace \
          pod-security.kubernetes.io/enforce=restricted \
          pod-security.kubernetes.io/enforce-version=latest \
          pod-security.kubernetes.io/audit=restricted \
          pod-security.kubernetes.io/audit-version=latest \
          pod-security.kubernetes.io/warn=restricted \
          pod-security.kubernetes.io/warn-version=latest --overwrite

        # To apply the same policy to multiple namespaces (edit the list as needed):
        for ns in team-a team-b production staging; do
          kubectl label namespace "$ns" \
            pod-security.kubernetes.io/enforce=restricted \
            pod-security.kubernetes.io/enforce-version=latest \
            pod-security.kubernetes.io/audit=restricted \
            pod-security.kubernetes.io/audit-version=latest \
            pod-security.kubernetes.io/warn=restricted \
            pod-security.kubernetes.io/warn-version=latest --overwrite
        done
        ```

        Example restrictive policy via a (legacy) PodSecurityPolicy-like admission controller (only if your cluster still uses it and you have the controller enabled):

        ```yaml theme={null}
        # Save as psp-no-privileged.yaml, then apply with:
        # kubectl apply -f psp-no-privileged.yaml
        apiVersion: policy/v1beta1
        kind: PodSecurityPolicy
        metadata:
          name: restricted-no-privileged
        spec:
          privileged: false
          allowPrivilegeEscalation: false
          requiredDropCapabilities:
            - ALL
          volumes:
            - 'configMap'
            - 'emptyDir'
            - 'projected'
            - 'secret'
            - 'downwardAPI'
            - 'persistentVolumeClaim'
          hostNetwork: false
          hostIPC: false
          hostPID: false
          runAsUser:
            rule: 'MustRunAsNonRoot'
          seLinux:
            rule: 'RunAsAny'
          supplementalGroups:
            rule: 'MustRunAs'
            ranges:
              - min: 1
                max: 65535
          fsGroup:
            rule: 'MustRunAs'
            ranges:
              - min: 1
                max: 65535
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: use-restricted-no-privileged
        rules:
          - apiGroups: ['policy']
            resources: ['podsecuritypolicies']
            verbs: ['use']
            resourceNames: ['restricted-no-privileged']
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: use-restricted-no-privileged
          namespace: my-workload-namespace
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: use-restricted-no-privileged
        subjects:
          - kind: Group
            name: system:serviceaccounts:my-workload-namespace
            apiGroup: rbac.authorization.k8s.io
        ```

        ```bash theme={null}
        # 2) Verification (no privileged containers in existing pods)
        # Run on: any machine with kubectl access

        kubectl get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | while read -r pod_name pod_namespace
        do
          kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | while read -r container
          do
            container_name=$(echo ${container} | jq -r '.name')
            container_privileged=$(echo ${container} | jq -r '.securityContext.privileged' | sed -e 's/null/notset/g')
            if [ "${container_privileged}" = "false" ] || [ "${container_privileged}" = "notset" ] ; then
              echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_privileged: ${container_privileged} is_compliant: true"
            else
              echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_privileged: ${container_privileged} is_compliant: false"
            fi
          done
        done
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Purpose: Minimize admission of privileged containers by enforcing a Pod Security policy
        #          (via Pod Security admission labels) or a fallback namespace-wide PSP-like
        #          restriction using a validating admission policy (for clusters that support it).
        # Scope:   Runs from any machine with kubectl access and current-context set appropriately.
        # Notes:   This is a MANUAL benchmark control. This script helps implement a common,
        #          restrictive policy, but you must review namespaces and exceptions yourself.

        set -euo pipefail

        # -----------------------------
        # Configuration (edit as needed)
        # -----------------------------

        # Namespaces to EXCLUDE from restriction (typically system/control-plane namespaces).
        # Add any namespaces that legitimately require privileged containers.
        EXCLUDED_NAMESPACES=(
          "kube-system"
          "kube-public"
          "kube-node-lease"
          "kube-admin"
          "kube-monitoring"
          "default"           # Remove this if you run user workloads in "default" and want it restricted
        )

        # Label key/value for Pod Security Admission. "restricted" blocks privileged containers.
        PSA_LABEL_KEY="pod-security.kubernetes.io/enforce"
        PSA_LABEL_VALUE="restricted"

        # Whether to attempt creating a validating admission policy as a fallback for clusters
        # without Pod Security Admission labels (set to "true" or "false").
        ENABLE_VALIDATING_FALLBACK="true"

        # Name/namespace for the validating admission policy resources (Kubernetes 1.27+).
        VAP_NAME="deny-privileged-containers"
        VAP_TEMPLATE_NAME="deny-privileged-containers-template"

        # -----------------------------------
        # Helpers
        # -----------------------------------

        kubectl_bin() {
          command -v kubectl
        }

        in_excluded_namespace() {
          local ns="$1"
          for e in "${EXCLUDED_NAMESPACES[@]}"; do
            if [[ "$ns" == "$e" ]]; then
              return 0
            fi
          done
          return 1
        }

        supports_pod_security_admission() {
          # Heuristic: check if namespace accepts pod-security.kubernetes.io/enforce label without error
          local test_ns="kube-system"
          if ! $(kubectl_bin) get ns "$test_ns" >/dev/null 2>&1; then
            return 1
          fi
          # Dry-run label; if it succeeds, assume PSA is available.
          if $(kubectl_bin) label ns "$test_ns" "${PSA_LABEL_KEY}=${PSA_LABEL_VALUE}" --dry-run=server >/dev/null 2>&1; then
            return 0
          fi
          return 1
        }

        kubectl_api_exists() {
          local api="$1"
          if $(kubectl_bin) api-resources --api-group="${api}" >/dev/null 2>&1; then
            return 0
          fi
          return 1
        }

        # -----------------------------------
        # 1. Enforce Pod Security "restricted" in workload namespaces (preferred)
        # -----------------------------------

        enforce_pod_security_admission() {
          echo "==> Enforcing Pod Security Admission 'restricted' in workload namespaces"

          local ns
          # Get all namespaces
          mapfile -t ALL_NS < <($(kubectl_bin) get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

          for ns in "${ALL_NS[@]}"; do
            if in_excluded_namespace "$ns"; then
              echo "Skipping excluded namespace: $ns"
              continue
            fi

            # Idempotent label application
            echo "Labeling namespace '$ns' with ${PSA_LABEL_KEY}=${PSA_LABEL_VALUE}"
            $(kubectl_bin) label namespace "$ns" "${PSA_LABEL_KEY}=${PSA_LABEL_VALUE}" --overwrite >/dev/null
          done
        }

        # -----------------------------------
        # 2. Fallback: ValidatingAdmissionPolicy to deny privileged pods (if supported)
        # -----------------------------------

        apply_validating_admission_policy() {
          if [[ "${ENABLE_VALIDATING_FALLBACK}" != "true" ]]; then
            echo "Validating admission fallback disabled; skipping."
            return 0
          fi

          if ! kubectl_api_exists "admissionregistration.k8s.io"; then
            echo "Cluster does not support admissionregistration.k8s.io; cannot apply validating admission policy."
            return 0
          fi

          echo "==> Applying ValidatingAdmissionPolicy to deny privileged containers (cluster-wide fallback)"

          # This policy denies creation/update of any Pod with any container.securityContext.privileged == true.
          # It is cluster-wide; you may need to refine the namespaces using matchConstraints.
          cat <<'EOF' | $(kubectl_bin) apply -f -
        apiVersion: admissionregistration.k8s.io/v1
        kind: ValidatingAdmissionPolicy
        metadata:
          name: deny-privileged-containers
        spec:
          failurePolicy: Fail
          matchConstraints:
            resourceRules:
            - apiGroups: [""]
              apiVersions: ["v1"]
              operations: ["CREATE","UPDATE"]
              resources: ["pods"]
          validations:
          - expression: "!(has(object.spec.containers) && object.spec.containers.exists(c, has(c.securityContext) && c.securityContext.privileged == true))"
            message: "Privileged containers are not allowed."
          - expression: "!(has(object.spec.initContainers) && object.spec.initContainers.exists(c, has(c.securityContext) && c.securityContext.privileged == true))"
            message: "Privileged init containers are not allowed."
        EOF

          # Create a binding that applies the policy cluster-wide
          cat <<'EOF' | $(kubectl_bin) apply -f -
        apiVersion: admissionregistration.k8s.io/v1
        kind: ValidatingAdmissionPolicyBinding
        metadata:
          name: deny-privileged-containers-binding
        spec:
          policyName: deny-privileged-containers
          validationActions: ["Deny"]
        EOF
        }

        # -----------------------------------
        # 3. Optional: Detect and report existing privileged containers
        # -----------------------------------

        report_existing_privileged_containers() {
          echo "==> Scanning for existing Pods with privileged containers (this does not change them)"
          $(kubectl_bin) get pods --all-namespaces -o custom-columns=POD_NAME:.metadata.name,POD_NAMESPACE:.metadata.namespace --no-headers | while read -r pod_name pod_namespace
          do
            $(kubectl_bin) get pod "${pod_name}" --namespace "${pod_namespace}" -o json | jq -c '.spec.containers[]' | while read -r container
            do
              container_name=$(echo "${container}" | jq -r '.name')
              container_privileged=$(echo "${container}" | jq -r '.securityContext.privileged' | sed -e 's/null/notset/g')
              if [ "${container_privileged}" = "false" ] || [ "${container_privileged}" = "notset" ] ; then
                echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_privileged: ${container_privileged} is_compliant: true"
              else
                echo "***pod_name: ${pod_name} container_name: ${container_name} pod_namespace: ${pod_namespace} is_container_privileged: ${container_privileged} is_compliant: false"
              fi
            done
          done
        }

        # -----------------------------------
        # 4. Main
        # -----------------------------------

        main() {
          if ! command -v jq >/dev/null 2>&1; then
            echo "jq is required for verification; please install jq and re-run."
            exit 1
          fi

          echo "==> Verifying kubectl connectivity"
          $(kubectl_bin) version --request-timeout=5s >/dev/null

          if supports_pod_security_admission; then
            enforce_pod_security_admission
          else
            echo "Pod Security Admission labels not supported (or dry-run server check failed)."
            apply_validating_admission_policy
          fi

          # Verification: rerun the supplied audit to show any remaining privileged containers.
          echo "==> Verification: listing containers and their privileged status after policy application"
          report_existing_privileged_containers

          echo "==> Completed. Review any 'is_compliant: false' lines and either:"
          echo "    - Remove 'privileged: true' from their Pod specs, or"
          echo "    - Move them into an explicitly excluded namespace and justify the exception."
        }

        main "$@"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
