> ## 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 Admission Containers Wishing Host Process ID Namespace

### More Info:

Do not generally permit containers to be run with the hostPID flag set to true.

### 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. **Identify pods using `hostPID: true` (any machine with kubectl access)**
           ```sh 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 [ "${pod_hostpid}" = "true" ]; then
               echo "NON-COMPLIANT: pod_name=${pod_name} pod_namespace=${pod_namespace} hostPID=${pod_hostpid}"
             fi
           done
           ```

        2. **Review and decide which workloads are allowed to use `hostPID` (any machine with kubectl access)**\
           For each non-compliant pod from step 1, inspect its purpose and manifests (Deployments, DaemonSets, etc.) and decide:
           * Is `hostPID` truly required (e.g., low-level node monitoring / debugging)?
           * If yes, explicitly document the exception (namespace, workload name, business owner, justification).
           * If no, plan to remove `hostPID` from the workload spec or replace it with a safer pattern.

        3. **Remove `hostPID: true` from workloads that do not require it (any machine with kubectl access)**\
           For each non-exempt workload, edit the owning controller and remove `hostPID: true` from `spec.template.spec`:
           ```sh theme={null}
           # Example: Deployment
           kubectl -n <NAMESPACE> edit deployment <DEPLOYMENT_NAME>

           # Example: DaemonSet
           kubectl -n <NAMESPACE> edit daemonset <DAEMONSET_NAME>
           ```
           In the editor, delete the line:
           ```yaml theme={null}
           hostPID: true
           ```
           Save and exit to trigger a rollout without hostPID.\
           For workloads managed via GitOps/IaC, make the same edit in the source manifests and re-apply:
           ```sh theme={null}
           kubectl apply -f <PATH_TO_CLEANED_MANIFEST>.yaml
           ```

        4. **Define a restrictive policy for each user-workload namespace (PodSecurityPolicy alternative: Pod Security Admission / admission controller) (any machine with kubectl access)**\
           Since this control is MANUAL, you must choose and implement a policy mechanism appropriate for your cluster (e.g., built-in Pod Security Admission, Kyverno, OPA/Gatekeeper). Example using built-in Pod Security Admission labels to disallow `hostPID` (applies if your cluster supports Pod Security Admission):
           ```sh theme={null}
           kubectl label namespace <NAMESPACE> \
             pod-security.kubernetes.io/enforce=restricted \
             pod-security.kubernetes.io/enforce-version=latest \
             --overwrite
           ```
           Then explicitly document exceptions (e.g., a dedicated namespace with a less restrictive policy) and ensure they are tightly controlled.

        5. **Optionally create a dedicated namespace for justified `hostPID` workloads (any machine with kubectl access)**\
           If you must allow some hostPID workloads, isolate them:
           ```sh theme={null}
           kubectl create namespace hostpid-exceptions
           ```
           Apply a clearly documented, less restrictive policy only to this namespace (mechanism depends on your chosen admission controller) and ensure RBAC limits who can deploy there.

        6. **Verification (any machine with kubectl access)**\
           Re-run the audit to confirm no unintended `hostPID: true` pods remain:
           ```sh 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 only explicitly approved exception workloads (if any) show `is_pod_hostpid: true` and are documented as such.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1) Identify namespaces with user workloads
        #    Run on: any machine with kubectl access
        kubectl get ns
        ```

        Create a baseline `PodSecurity` `Baseline` / `restricted` combo that disallows `hostPID` everywhere
        (except where you explicitly override it later):

        ```yaml theme={null}
        # 2) Apply cluster-wide default: baseline+restricted (no hostPID)
        #    Run on: any machine with kubectl access
        #    Save as: podsecurity-defaults.yaml
        apiVersion: v1
        kind: Namespace
        metadata:
          name: default
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: workloads
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: apps
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: staging
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: prod
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: dev
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: qa
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: ci
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: cd
        ---
        apiVersion: v1
        kind: Namespace
        metadata:
          name: test
        ---
        # Example of labels to enforce Pod Security admission:
        # Adjust the list of Namespace objects above to match your real user-workload namespaces
        # and keep *only* the ones you actually have. Then apply labels with this patch command instead
        ```

        In practice you do not recreate namespaces; you label existing ones. For each namespace that should NOT allow `hostPID`, run:

        ```bash theme={null}
        # 3) Enforce baseline+restricted Pod Security in user-workload namespaces
        #    Run on: any machine with kubectl access

        # Example for namespace "apps" – repeat for each user-workload namespace
        kubectl label ns apps \
          pod-security.kubernetes.io/enforce=baseline \
          pod-security.kubernetes.io/enforce-version=latest \
          pod-security.kubernetes.io/audit=restricted \
          pod-security.kubernetes.io/audit-version=latest \
          --overwrite
        ```

        For the rare namespace that must allow `hostPID` (e.g. system diagnostics), you consciously
        opt out by *not* setting these labels or by setting a lower level and documenting the exception:

        ```bash theme={null}
        # 4) Example: mark "ops-tools" as allowing hostPID (documented exception)
        kubectl label ns ops-tools \
          pod-security.kubernetes.io/enforce=privileged \
          pod-security.kubernetes.io/enforce-version=latest \
          --overwrite
        ```

        If you do not use PodSecurity admission (older clusters), you must instead use a
        policy engine such as Gatekeeper/OPA or Kyverno. Example Kyverno policy
        (disallow `hostPID` except in explicitly allowed namespaces):

        ```yaml theme={null}
        # 5) Kyverno ClusterPolicy to block hostPID pods except in allowed namespaces
        #    Run on: any machine with kubectl access
        #    Save as: disallow-hostpid.yaml
        apiVersion: kyverno.io/v1
        kind: ClusterPolicy
        metadata:
          name: disallow-hostpid
        spec:
          validationFailureAction: Enforce
          background: true
          rules:
          - name: block-hostpid
            match:
              any:
              - resources:
                  kinds:
                  - Pod
                  namespaces:
                  - "*"
            exclude:
              any:
              - resources:
                  namespaces:
                  - kube-system
                  - ops-tools          # add any exception namespaces here explicitly
            validate:
              message: "Use of hostPID is restricted; remove spec.hostPID or use an approved namespace."
              pattern:
                spec:
                  hostPID: "false"
        ```

        Apply the policy:

        ```bash theme={null}
        kubectl apply -f disallow-hostpid.yaml
        ```

        Verification (matches the audit logic):

        ```bash theme={null}
        # 6) Verify there are no pods running with hostPID=true
        #    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
          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
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Minimize admission of containers with hostPID=true by applying a
        #   namespace-level restriction (Pod Security Admission or PSP fallback).
        #
        # Requirements:
        #   - Run on any machine with kubectl access and current-context pointing to the target cluster.
        #   - kubectl v1.25+ recommended (PSA annotations). For older clusters with PodSecurityPolicy
        #     still enabled, this script also creates a restrictive PSP + RBAC as a fallback.
        #
        # Behavior:
        #   - Skips system namespaces.
        #   - For each remaining namespace, applies:
        #       * Pod Security Admission annotations enforcing baseline level.
        #         (baseline implicitly disallows hostPID=true).
        #   - Creates a baseline PSP + RBAC only if the API exists and not already present.
        #   - Re-runs safely (idempotent).
        #   - Prints verification of pods with hostPID=true at the end.

        set -euo pipefail

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

        # Namespaces to skip (system/control-plane)
        SKIP_NAMESPACES=(
          "kube-system"
          "kube-public"
          "kube-node-lease"
          "default"        # remove from this list if you run user workloads in 'default'
        )

        PSP_NAME="restrict-hostpid-psp"
        PSP_ROLE_NAME="restrict-hostpid-psp-role"
        PSP_ROLEBINDING_NAME="restrict-hostpid-psp-rb"

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

        ns_in_skip_list() {
          local ns="$1"
          for s in "${SKIP_NAMESPACES[@]}"; do
            if [[ "$ns" == "$s" ]]; then
              return 0
            fi
          done
          return 1
        }

        api_exists() {
          local api="$1"
          if kubectl api-resources --api-group "$(cut -d'/' -f1 <<<"$api")" --no-headers 2>/dev/null | grep -q "$(cut -d'/' -f2 <<<"$api")"; then
            return 0
          fi
          return 1
        }

        # -----------------------------
        # Pod Security Admission (preferred)
        # -----------------------------

        apply_psa_annotations() {
          echo "Applying Pod Security Admission annotations (baseline) to non-system namespaces..."

          # Check if PSA is supported (Kubernetes >= 1.23 typically)
          if ! kubectl api-resources | grep -q "podsecuritypolicies.authorization.k8s.io"; then
            # Even if PSP API isn't present, PSA annotations are just labels/annotations and do not
            # require an API resource. We'll always apply annotations; enforcement depends on the cluster config.
            :
          fi

          # Annotate each non-system namespace
          while IFS= read -r ns; do
            ns_in_skip_list "$ns" && continue

            echo "  - Namespace: $ns"

            # Patch namespace with PSA labels/annotations (idempotent).
            # baseline disallows hostPID; enforce strict for workloads.
            kubectl label namespace "$ns" \
              pod-security.kubernetes.io/enforce=baseline \
              pod-security.kubernetes.io/enforce-version=latest \
              --overwrite

            kubectl annotate namespace "$ns" \
              pod-security.kubernetes.io/warn=baseline \
              pod-security.kubernetes.io/audit=baseline \
              pod-security.kubernetes.io/warn-version=latest \
              pod-security.kubernetes.io/audit-version=latest \
              --overwrite

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

        # -----------------------------
        # Optional fallback: PodSecurityPolicy (legacy clusters only)
        # -----------------------------

        ensure_restrictive_psp() {
          # Only if the PSP API exists
          if ! kubectl api-versions 2>/dev/null | grep -q "^policy/v1beta1$"; then
            echo "PodSecurityPolicy API not present; skipping PSP fallback."
            return 0
          fi

          echo "PodSecurityPolicy API detected; ensuring restrictive PSP for hostPID..."

          # Create PSP if it doesn't exist
          if ! kubectl get psp "$PSP_NAME" >/dev/null 2>&1; then
            cat <<EOF | kubectl apply -f -
        apiVersion: policy/v1beta1
        kind: PodSecurityPolicy
        metadata:
          name: ${PSP_NAME}
        spec:
          privileged: false
          hostPID: false
          hostNetwork: false
          hostIPC: 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
          else
            echo "  PSP ${PSP_NAME} already exists; leaving as-is."
          fi

          # Create ClusterRole allowing use of the PSP
          if ! kubectl get clusterrole "$PSP_ROLE_NAME" >/dev/null 2>&1; then
            cat <<EOF | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: ${PSP_ROLE_NAME}
        rules:
          - apiGroups: ['policy']
            resources: ['podsecuritypolicies']
            verbs: ['use']
            resourceNames: ['${PSP_NAME}']
        EOF
          else
            echo "  ClusterRole ${PSP_ROLE_NAME} already exists; leaving as-is."
          fi

          # Bind the ClusterRole to all authenticated users (typical baseline)
          if ! kubectl get clusterrolebinding "$PSP_ROLEBINDING_NAME" >/dev/null 2>&1; then
            cat <<EOF | kubectl apply -f -
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: ${PSP_ROLEBINDING_NAME}
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: ${PSP_ROLE_NAME}
        subjects:
          - kind: Group
            apiGroup: rbac.authorization.k8s.io
            name: system:authenticated
        EOF
          else
            echo "  ClusterRoleBinding ${PSP_ROLEBINDING_NAME} already exists; leaving as-is."
          fi
        }

        # -----------------------------
        # Main
        # -----------------------------

        echo "Starting remediation for hostPID usage..."

        apply_psa_annotations
        ensure_restrictive_psp

        # -----------------------------
        # Verification (from benchmark audit)
        # -----------------------------

        echo
        echo "Verification: scanning all pods for hostPID=true ..."
        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 [ -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

        echo
        echo "NOTE:"
        echo "- Existing pods with hostPID=true will still show as non-compliant until recreated."
        echo "- New pods in annotated namespaces should be prevented from using hostPID=true, subject to your cluster's admission configuration."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
