> ## 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:

Sharing the host PID namespace lets a container see and interact with all host processes, aiding escape and escalation. Restrict hostPID pods.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List and review current Pods using `hostPID`** (any machine with kubectl access)
           ```bash theme={null}
           kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.hostPID==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
           ```
           For each listed Pod, decide if host PID access is strictly required. If not, plan to remove it; if yes, note the namespace so you can design exception policies (e.g., via labels).

        2. **Create a restrictive `PodSecurityPolicy` or `Pod Security Standards`-style control (if PSP still in use)** (any machine with kubectl access)\
           If you still use PodSecurityPolicy, create one that forbids hostPID:
           ```bash theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: policy/v1beta1
           kind: PodSecurityPolicy
           metadata:
             name: restricted-no-hostpid
           spec:
             hostPID: false
             privileged: false
             runAsUser:
               rule: 'MustRunAsNonRoot'
             seLinux:
               rule: 'RunAsAny'
             fsGroup:
               rule: 'RunAsAny'
             supplementalGroups:
               rule: 'RunAsAny'
             volumes:
             - 'configMap'
             - 'emptyDir'
             - 'projected'
             - 'secret'
             - 'downwardAPI'
             - 'persistentVolumeClaim'
           EOF
           ```
           If your cluster instead uses Pod Security Admission (PSA), apply a namespace-level policy that disallows host namespaces. For example, enforce `restricted` on a namespace:
           ```bash theme={null}
           kubectl label namespace my-workload-namespace \
             pod-security.kubernetes.io/enforce=restricted \
             --overwrite
           ```
           Repeat for each user-workload namespace, adjusting names as needed.

        3. **Bind the policy to user-workload namespaces (if using PSP)** (any machine with kubectl access)
           ```bash theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: rbac.authorization.k8s.io/v1
           kind: ClusterRole
           metadata:
             name: use-restricted-no-hostpid-psp
           rules:
           - apiGroups: ['policy']
             resources: ['podsecuritypolicies']
             verbs: ['use']
             resourceNames: ['restricted-no-hostpid']
           ---
           apiVersion: rbac.authorization.k8s.io/v1
           kind: RoleBinding
           metadata:
             name: use-restricted-no-hostpid-psp
             namespace: my-workload-namespace
           subjects:
           - kind: Group
             name: system:serviceaccounts:my-workload-namespace
             apiGroup: rbac.authorization.k8s.io
           roleRef:
             kind: ClusterRole
             name: use-restricted-no-hostpid-psp
             apiGroup: rbac.authorization.k8s.io
           EOF
           ```
           Repeat the `RoleBinding` stanza for each user-workload namespace by changing `namespace:` and the `system:serviceaccounts:<namespace>` group.

        4. **Tighten admission using a validating admission policy (if PSA/PSP are not applicable)** (any machine with kubectl access)\
           If you rely on a generic admission controller (e.g., ValidatingAdmissionPolicy in newer Kubernetes), create a policy that rejects hostPID Pods, then selectively exempt namespaces that truly require it:
           ```bash theme={null}
           cat << 'EOF' | kubectl apply -f -
           apiVersion: admissionregistration.k8s.io/v1
           kind: ValidatingWebhookConfiguration
           metadata:
             name: deny-hostpid-pods
           webhooks:
           - name: deny-hostpid-pods.example.com
             admissionReviewVersions: ["v1"]
             sideEffects: None
             failurePolicy: Fail
             rules:
             - apiGroups: [""]
               apiVersions: ["v1"]
               operations: ["CREATE","UPDATE"]
               resources: ["pods"]
             namespaceSelector:
               matchExpressions:
               - key: allow-hostpid
                 operator: NotIn
                 values: ["true"]
             clientConfig:
               # POINT THIS TO YOUR ACTUAL WEBHOOK SERVICE IMPLEMENTATION
               service:
                 namespace: policy-system
                 name: hostpid-deny-webhook
                 path: /validate
           EOF
           ```
           Implement the webhook to reject any Pod with `.spec.hostPID == true`. Label only the namespaces that genuinely require hostPID with `allow-hostpid=true` to exempt them.

        5. **Update or recreate non-essential hostPID Pods without hostPID** (any machine with kubectl access)\
           For any Pod/Deployment/DaemonSet/Job where hostPID is not strictly required, edit the manifest to remove or set `hostPID: false`, then apply:
           ```bash theme={null}
           kubectl -n <namespace> get deployment <name> -o yaml > /tmp/deploy-no-hostpid.yaml
           sed -i 's/hostPID: true/hostPID: false/' /tmp/deploy-no-hostpid.yaml
           kubectl apply -f /tmp/deploy-no-hostpid.yaml
           ```
           For standalone Pods, delete and recreate them from updated manifests without `hostPID: true`.

        6. **Verify no non-exempt Pods use hostPID** (any machine with kubectl access)
           ```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
             pod_hostpid=$(kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o jsonpath='{.spec.hostPID}' 2>/dev/null)
             if [ -z "${pod_hostpid}" ]; then
               pod_hostpid="false"
               echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostpid: ${pod_hostpid} is_compliant: true"
             else
               echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostpid: ${pod_hostpid} is_compliant: false"
             fi
           done
           ```
           Confirm that any `is_compliant: false` Pods exist only in namespaces you have explicitly designated as allowed to use hostPID and that they are strictly necessary.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Create a baseline restrictive PodSecurityPolicy (if your cluster still uses PSP)
        #    This denies hostPID by default.
        #    Run on: any machine with kubectl access.

        cat <<'EOF' > psp-deny-hostpid.yaml
        apiVersion: policy/v1beta1
        kind: PodSecurityPolicy
        metadata:
          name: deny-hostpid
        spec:
          privileged: false
          hostPID: false
          hostIPC: false
          hostNetwork: false
          seLinux:
            rule: RunAsAny
          runAsUser:
            rule: RunAsAny
          fsGroup:
            rule: RunAsAny
          supplementalGroups:
            rule: RunAsAny
          volumes:
          - '*'
        EOF

        kubectl apply -f psp-deny-hostpid.yaml
        ```

        ```bash theme={null}
        # 2) Bind this PSP to a namespace with user workloads (example: "production").
        #    Replace "production" with each target namespace.
        #    Run on: any machine with kubectl access.

        NAMESPACE=production

        cat <<EOF | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: Role
        metadata:
          name: use-deny-hostpid-psp
          namespace: ${NAMESPACE}
        rules:
        - apiGroups: ['policy']
          resources: ['podsecuritypolicies']
          verbs:     ['use']
          resourceNames: ['deny-hostpid']
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          name: use-deny-hostpid-psp
          namespace: ${NAMESPACE}
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: Role
          name: use-deny-hostpid-psp
        subjects:
        - apiGroup: rbac.authorization.k8s.io
          kind: Group
          name: system:serviceaccounts:${NAMESPACE}
        EOF
        ```

        ```bash theme={null}
        # 3) (Alternative / additional) Use Pod Security Admission via labels to restrict hostPID.
        #    Use "restricted" or stricter for all user namespaces (example: "production").
        #    Run on: any machine with kubectl access.

        kubectl label namespace production \
          pod-security.kubernetes.io/enforce=restricted \
          pod-security.kubernetes.io/enforce-version=latest \
          --overwrite
        ```

        ```bash theme={null}
        # 4) (Optional) Example: secure Pod manifest WITHOUT hostPID for user workloads.
        #    Ensure all application manifests in user namespaces omit hostPID or set it to false.

        cat <<'EOF' > example-app-pod.yaml
        apiVersion: v1
        kind: Pod
        metadata:
          name: example-app
          namespace: production
        spec:
          hostPID: false
          containers:
          - name: app
            image: nginx:stable
        EOF

        kubectl apply -f example-app-pod.yaml
        ```

        ```bash theme={null}
        # 5) Verification: list all Pods with hostPID=true to confirm none exist in user namespaces.
        #    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) hostPID=true"' || true
        ```
      </Accordion>

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

        # This script:
        # - Creates a Pod Security Policy–style restriction using Pod Security Admission (PSA) via labels/Policy/PSP replacement
        # - For each namespace with user workloads, it:
        #   * Labels the namespace with a restricted Pod Security level (baseline or restricted)
        #   * Creates/patches a validating admission policy (if supported) or a validating webhook
        #
        # NOTE:
        # - This is a MANUAL benchmark control: different clusters use different admission stacks.
        # - This script implements a conservative, Kubernetes-native control using Pod Security Admission labels
        #   and a validating admission policy if available. Review carefully before using in production.

        # -------- CONFIGURATION --------

        # Namespaces to ignore (system and infrastructure)
        EXCLUDED_NAMESPACES=(
          "kube-system"
          "kube-public"
          "kube-node-lease"
          "local-path-storage"
          "default"          # remove this if you run user workloads in 'default'
        )

        # Pod Security level to enforce; choose "baseline" or "restricted"
        POD_SECURITY_LEVEL="baseline"

        # Label key for Pod Security Admission
        POD_SECURITY_ENFORCE_LABEL="pod-security.kubernetes.io/enforce"

        # ValidatingAdmissionPolicy name (for clusters >=1.26 supporting it)
        VAP_NAME="deny-hostpid-pods"
        VAP_BINDING_NAME="deny-hostpid-pods-binding"

        # -------- FUNCTIONS --------

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

        kubectl_safe() {
          kubectl "$@" 2>/dev/null
        }

        # -------- PRECHECKS --------

        echo "Checking kubectl access..."
        kubectl version --short >/dev/null

        echo "Determining cluster support for ValidatingAdmissionPolicy..."
        if kubectl_safe api-resources | grep -q "^validatingadmissionpolicies"; then
          HAS_VAP="true"
        else
          HAS_VAP="false"
        fi
        echo "ValidatingAdmissionPolicy supported: ${HAS_VAP}"

        # -------- STEP 1: Label namespaces with Pod Security Admission --------
        # Run on: any machine with kubectl access

        echo "Labeling namespaces with Pod Security Admission level: ${POD_SECURITY_LEVEL}"

        ALL_NAMESPACES=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

        while read -r NS; do
          [[ -z "$NS" ]] && continue
          if is_excluded_ns "$NS"; then
            echo "Skipping excluded namespace: ${NS}"
            continue
          fi

          # Skip namespaces without user pods
          POD_COUNT=$(kubectl get pods -n "$NS" --no-headers 2>/dev/null | wc -l | tr -d ' ')
          if [[ "$POD_COUNT" -eq 0 ]]; then
            echo "Skipping namespace with no pods: ${NS}"
            continue
          fi

          CURRENT_LABEL=$(kubectl get ns "$NS" -o jsonpath="{.metadata.labels.${POD_SECURITY_ENFORCE_LABEL}}" 2>/dev/null || echo "")

          if [[ "$CURRENT_LABEL" == "${POD_SECURITY_LEVEL}" ]]; then
            echo "Namespace ${NS} already labeled ${POD_SECURITY_ENFORCE_LABEL}=${POD_SECURITY_LEVEL}"
          else
            echo "Labeling namespace ${NS} with ${POD_SECURITY_ENFORCE_LABEL}=${POD_SECURITY_LEVEL}"
            kubectl label ns "$NS" "${POD_SECURITY_ENFORCE_LABEL}=${POD_SECURITY_LEVEL}" --overwrite
          fi
        done <<< "${ALL_NAMESPACES}"

        # -------- STEP 2: Create/Update ValidatingAdmissionPolicy (if supported) --------
        # Run on: any machine with kubectl access

        if [[ "${HAS_VAP}" == "true" ]]; then
          echo "Applying ValidatingAdmissionPolicy to deny hostPID pods..."

          cat <<'EOF' | kubectl apply -f -
        apiVersion: admissionregistration.k8s.io/v1
        kind: ValidatingAdmissionPolicy
        metadata:
          name: deny-hostpid-pods
        spec:
          matchConstraints:
            resourceRules:
              - apiGroups: [""]
                apiVersions: ["v1"]
                operations: ["CREATE", "UPDATE"]
                resources: ["pods"]
          validations:
            - expression: "!(has(object.spec.hostPID) && object.spec.hostPID == true)"
              message: "Creating pods with hostPID=true is not allowed by policy"
              reason: "Forbidden"
        EOF

          cat <<EOF | kubectl apply -f -
        apiVersion: admissionregistration.k8s.io/v1
        kind: ValidatingAdmissionPolicyBinding
        metadata:
          name: ${VAP_BINDING_NAME}
        spec:
          policyName: ${VAP_NAME}
          matchResources:
            namespaceSelector: {}
          validationActions: ["Deny"]
        EOF

        else
          echo "Cluster does not support ValidatingAdmissionPolicy;"
          echo "you must manually implement an alternative admission control (e.g. Gatekeeper/PSP replacement)."
        fi

        # -------- STEP 3: Verification --------
        # Run on: any machine with kubectl access

        echo
        echo "Verifying that existing pods do not use hostPID=true..."

        NONCOMPLIANT=false
        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
          pod_hostpid=$(kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o jsonpath='{.spec.hostPID}' 2>/dev/null || true)
          if [[ -n "${pod_hostpid}" && "${pod_hostpid}" == "true" ]]; then
            echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostpid: ${pod_hostpid} is_compliant: false"
            NONCOMPLIANT=true
          fi
        done

        if [[ "${NONCOMPLIANT}" == "false" ]]; then
          echo "All existing pods are compliant (hostPID not set or false)."
        else
          echo "Some existing pods are non-compliant; they must be manually reviewed and recreated without hostPID=true."
        fi

        echo
        echo "To test enforcement, try creating a pod with spec.hostPID=true in a labeled user namespace; it should be denied."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
