> ## 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 Containers Sharing The Host Process ID Namespace

### More Info:

Containers sharing the host PID namespace can view and interact with all processes on the node. Restrict admission of hostPID containers via namespace policies.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List all namespaces that contain user workloads (exclude system namespaces)\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get ns
           ```
           Decide which namespaces should be protected (e.g., everything except kube-system, kube-public, kube-node-lease, etc.).

        2. For each target namespace, create or update a Pod Security admission label set to `restricted` (which forbids `hostPID: true`)\
           Run on: any machine with kubectl access\
           Replace `<NAMESPACE>` with the actual namespace name:
           ```bash theme={null}
           kubectl label namespace <NAMESPACE> \
             pod-security.kubernetes.io/enforce=restricted \
             pod-security.kubernetes.io/enforce-version=latest \
             --overwrite
           ```

        3. Optionally add warnings/audit labels (recommended to catch violations before enforcement)\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl label namespace <NAMESPACE> \
             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
           ```

        4. For clusters not using Pod Security Admission and instead using an existing Validating/MutatingWebhookPolicy controller (e.g., OPA Gatekeeper, Kyverno), create a policy in that system denying `spec.hostPID: true` in the target namespaces.\
           Run on: any machine with kubectl access\
           Example Kyverno policy manifest (save as `deny-hostpid.yaml` and apply):
           ```yaml theme={null}
           apiVersion: kyverno.io/v1
           kind: ClusterPolicy
           metadata:
             name: disallow-hostpid
           spec:
             validationFailureAction: enforce
             rules:
               - name: deny-hostpid
                 match:
                   any:
                     - resources:
                         kinds:
                           - Pod
                 validate:
                   message: "Sharing the host PID namespace (hostPID) is not allowed."
                   pattern:
                     spec:
                       hostPID: "false"
           ```
           Apply it:
           ```bash theme={null}
           kubectl apply -f deny-hostpid.yaml
           ```

        5. Review and update existing manifests or Helm charts for user workloads to remove `hostPID: true` where it is not strictly required.
           * Search manifests locally:
             ```bash theme={null}
             grep -Rni "hostPID" .
             ```
           * For any Pod/Deployment/DaemonSet/etc. manifest that contains `hostPID: true`, edit the file and set:
             ```yaml theme={null}
             spec:
               hostPID: false
             ```
           Then re-apply:
           ```bash theme={null}
           kubectl apply -f <UPDATED_MANIFEST_FILE>
           ```

        6. Verification (no pods with `hostPID: true` should exist)\
           Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | \
             jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end'
           ```
           Confirm the output is:
           ```text theme={null}
           NO_HOSTPID
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Create a baseline Pod Security Admission configuration that disallows hostPID
        #    Run on: any machine with kubectl access

        cat << 'EOF' > psa-hostpid-restrict.yaml
        apiVersion: policy/v1
        kind: PodSecurityPolicy
        metadata:
          name: restricted-no-hostpid
          labels:
            app.kubernetes.io/name: restricted-no-hostpid
        spec:
          privileged: false
          hostPID: false
          hostIPC: false
          hostNetwork: false
          allowPrivilegeEscalation: false
          requiredDropCapabilities:
            - ALL
          volumes:
            - 'configMap'
            - 'emptyDir'
            - 'projected'
            - 'secret'
            - 'downwardAPI'
            - 'persistentVolumeClaim'
          runAsUser:
            rule: 'MustRunAsNonRoot'
          seLinux:
            rule: 'RunAsAny'
          fsGroup:
            rule: 'MustRunAs'
            ranges:
              - min: 1
                max: 65535
          supplementalGroups:
            rule: 'MustRunAs'
            ranges:
              - min: 1
                max: 65535
        EOF

        # Apply the PodSecurityPolicy (only works if PSP admission is enabled in your cluster)
        kubectl apply -f psa-hostpid-restrict.yaml
        ```

        ```bash theme={null}
        # 2) Bind the PSP to each namespace with user workloads
        #    Replace <NAMESPACE> with each user-workload namespace name.
        #    Run on: any machine with kubectl access

        NAMESPACE=<NAMESPACE>

        kubectl create role psp-restricted-no-hostpid \
          --verb=use \
          --resource=podsecuritypolicies \
          --resource-name=restricted-no-hostpid \
          -n "$NAMESPACE"

        kubectl create rolebinding psp-restricted-no-hostpid-binding \
          --role=psp-restricted-no-hostpid \
          --group=system:serviceaccounts:"$NAMESPACE" \
          -n "$NAMESPACE"
        ```

        ```bash theme={null}
        # 3) (Alternative / in addition) Enforce Pod Security Admission labels to restrict hostPID
        #    For each user-workload namespace, label with at least "restricted" policy
        #    Run on: any machine with kubectl access

        NAMESPACE=<NAMESPACE>

        kubectl label namespace "$NAMESPACE" \
          pod-security.kubernetes.io/enforce=restricted \
          --overwrite

        kubectl label namespace "$NAMESPACE" \
          pod-security.kubernetes.io/audit=restricted \
          --overwrite

        kubectl label namespace "$NAMESPACE" \
          pod-security.kubernetes.io/warn=restricted \
          --overwrite
        ```

        ```bash theme={null}
        # 4) Optional: Immediately remove any existing pods that are using hostPID
        #    WARNING: This deletes running pods; review carefully before running.
        #    Run on: any machine with kubectl access

        kubectl get pods --all-namespaces -o json | \
          jq -r '.items[] | select(.spec.hostPID == true) | [.metadata.namespace, .metadata.name] | @tsv' | \
          while IFS=$'\t' read -r ns name; do
            kubectl delete pod "$name" -n "$ns"
          done
        ```

        ```bash theme={null}
        # 5) Verification (from the benchmark audit)
        #    Run on: any machine with kubectl access

        kubectl get pods --all-namespaces -o json | \
          jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        set -euo pipefail

        # This script:
        # - Adds or updates a PodSecurityPolicy and/or Namespace-level policy object
        #   that forbids hostPID usage in all user namespaces.
        # - Skips system/control-plane namespaces.
        # - Verifies that no pods with hostPID=true remain (or reports if any do).
        #
        # Requirements:
        # - Run on any machine with kubectl access to the cluster.
        # - kubectl must be configured with sufficient RBAC to create/patch the used objects.
        #
        # NOTE:
        # - This implements the benchmark guidance by restricting admission of hostPID
        #   containers via namespace-level policy resources.
        # - Two mechanisms are covered, use whichever your cluster supports:
        #   * Pod Security Admission (PSA) labels on Namespaces (v1.23+ clusters using PSA)
        #   * Or, as a fallback, a restrictive PodSecurityPolicy bound per namespace
        #
        # The script is idempotent and safe to re-run.

        # ------------------------
        # Configuration
        # ------------------------

        # Namespaces to ignore (system/control-plane)
        EXCLUDE_NAMESPACES=(
          kube-system
          kube-public
          kube-node-lease
          default
        )

        # Label values for Pod Security Admission (most strict: restricted:enforce)
        PSA_ENFORCE_LEVEL="restricted"
        PSA_AUDIT_LEVEL="restricted"
        PSA_WARN_LEVEL="restricted"

        # Names for PSP resources (if PSP is enabled in your cluster)
        PSP_NAME="restrict-hostpid-psp"
        PSP_CLUSTERROLE_NAME="restrict-hostpid-psp-role"

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

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

        have_psa() {
          # Heuristic: if PodSecurity admission plugin is present, Namespaces usually
          # accept pod-security.kubernetes.io/* labels; there's no direct API.
          # We simply try to label a dummy in dry-run mode.
          if kubectl label namespace default \
            pod-security.kubernetes.io/enforce="${PSA_ENFORCE_LEVEL}" \
            --dry-run=server >/dev/null 2>&1; then
            return 0
          fi
          return 1
        }

        have_psp() {
          if kubectl api-resources | grep -q "^podsecuritypolicies"; then
            return 0
          fi
          return 1
        }

        # ------------------------
        # Step 1: Create/update cluster-wide objects for PSP path (if applicable)
        # ------------------------

        setup_psp() {
          # Create or update the PodSecurityPolicy that forbids hostPID
          cat <<'EOF' | kubectl apply -f -
        apiVersion: policy/v1beta1
        kind: PodSecurityPolicy
        metadata:
          name: restrict-hostpid-psp
        spec:
          privileged: false
          hostPID: false
          hostIPC: false
          hostNetwork: false
          allowPrivilegeEscalation: false
          requiredDropCapabilities:
            - ALL
          volumes:
            - 'configMap'
            - 'emptyDir'
            - 'projected'
            - 'secret'
            - 'downwardAPI'
            - 'persistentVolumeClaim'
          runAsUser:
            rule: 'MustRunAsNonRoot'
          seLinux:
            rule: 'RunAsAny'
          fsGroup:
            rule: 'RunAsAny'
          supplementalGroups:
            rule: 'RunAsAny'
        EOF

          # Create a ClusterRole that allows use of this PSP
          cat <<EOF | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: ${PSP_CLUSTERROLE_NAME}
        rules:
          - apiGroups: ['policy']
            resources: ['podsecuritypolicies']
            verbs: ['use']
            resourceNames: ['${PSP_NAME}']
        EOF
        }

        bind_psp_to_namespace() {
          local ns="$1"

          cat <<EOF | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: use-${PSP_NAME}
          namespace: ${ns}
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: ${PSP_CLUSTERROLE_NAME}
        subjects:
          - kind: Group
            name: system:serviceaccounts:${ns}
            apiGroup: rbac.authorization.k8s.io
        EOF
        }

        # ------------------------
        # Step 2: Apply namespace-level restrictions
        # ------------------------

        main() {
          echo "Discovering namespaces..."
          mapfile -t namespaces < <(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

          use_psa=false
          use_psp=false

          if have_psa; then
            echo "Pod Security Admission detected; will enforce restricted profile via namespace labels."
            use_psa=true
          elif have_psp; then
            echo "PodSecurityPolicy detected; will create PSP and bind per namespace."
            use_psp=true
            setup_psp
          else
            echo "WARNING: Neither Pod Security Admission nor PodSecurityPolicy appear to be available."
            echo "You must implement an alternative admission control (e.g. OPA/Gatekeeper, Kyverno)"
            echo "to enforce 'hostPID: false' per namespace. This script cannot enforce that automatically."
          fi

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

            echo "Processing namespace: ${ns}"

            if $use_psa; then
              # Label namespace with restrictive PSA; idempotent.
              kubectl label namespace "${ns}" \
                "pod-security.kubernetes.io/enforce=${PSA_ENFORCE_LEVEL}" \
                "pod-security.kubernetes.io/audit=${PSA_AUDIT_LEVEL}" \
                "pod-security.kubernetes.io/warn=${PSA_WARN_LEVEL}" \
                --overwrite
            fi

            if $use_psp; then
              bind_psp_to_namespace "${ns}"
            fi
          done

          # ------------------------
          # Step 3: Verification
          # ------------------------
          echo "Verifying that no pods with hostPID=true remain admitted..."
          result="$(
            kubectl get pods --all-namespaces -o json | \
              jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end'
          )"

          if [[ "$result" == "NO_HOSTPID" ]]; then
            echo "Verification PASSED: no pods with hostPID=true are present."
          else
            echo "Verification WARNING: existing pods with hostPID=true are still present."
            echo "New hostPID pods should now be rejected in protected namespaces, but you must:"
            echo "- Identify and delete/migrate those pods, or"
            echo "- Explicitly allow hostPID only where absolutely required."
          fi
        }

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