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

# Pods Should Not Share Host Namespaces

### More Info:

Verifies no pod sets hostPID, hostIPC or hostNetwork. Sharing a host namespace breaks the isolation boundary between the pod and the node.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* Cloudanix Best Practice

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. List all non-system pods that share a host namespace (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.nodeName // "") as $node
             | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
             | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
             | (.spec.hostPID // false) as $hostPID
             | (.spec.hostIPC // false) as $hostIPC
             | (.spec.hostNetwork // false) as $hostNet
             | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
               + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
               + (if $node   == ""   then "" else " node=\($node)" end)
               + (if $labels == ""   then "" else " labels=\($labels)" end)
               + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
               + " hostPID=\($hostPID) hostIPC=\($hostIPC) hostNetwork=\($hostNet)"
               + " is_compliant=\(if ($hostPID or $hostIPC or $hostNet) then "false" else "true" end)"
             ] as $rows
             | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
           ```

        2. For each non-compliant pod, identify and edit its owning workload (Deployment/DaemonSet/StatefulSet/Job/CronJob) in its namespace (run on any machine with kubectl access). Example for a Deployment:
           ```bash theme={null}
           kubectl -n <namespace> get pod <pod-name> -o jsonpath='{.metadata.ownerReferences[0].kind}{" "}{.metadata.ownerReferences[0].name}{"\n"}'

           kubectl -n <namespace> edit <OwnerKind>/<OwnerName>
           ```
           In the opened manifest, locate `.spec.template.spec` and ensure:
           ```yaml theme={null}
           spec:
             # remove these lines if present, or set them to false
             hostPID: false
             hostIPC: false
             hostNetwork: false
           ```
           Save and exit to apply the change. Kubernetes will recreate pods with the updated spec.

        3. If a non-compliant pod is standalone (no ownerReferences), fetch its manifest, modify, and re-create it (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n <namespace> get pod <pod-name> -o yaml > /tmp/pod-fixed.yaml
           ```
           Edit `/tmp/pod-fixed.yaml` and under `spec:` remove `hostPID`, `hostIPC`, `hostNetwork` fields or set them to `false`, and delete fields that must not be reused (`metadata.resourceVersion`, `metadata.uid`, `metadata.creationTimestamp`, `metadata.managedFields`, `status`). Then:
           ```bash theme={null}
           kubectl -n <namespace> delete pod <pod-name>
           kubectl -n <namespace> apply -f /tmp/pod-fixed.yaml
           ```

        4. If the pod is managed by GitOps or other IaC, also update the source manifest so changes are not reverted (run in your IaC workflow environment). In the relevant YAML file, under the pod template:
           ```yaml theme={null}
           spec:
             # ensure these are omitted or explicitly set to false
             hostPID: false
             hostIPC: false
             hostNetwork: false
           ```
           Commit and push through your normal deployment pipeline.

        5. For workloads that genuinely require host namespaces (for example, certain node-level monitoring/diagnostics agents), perform a risk review and formally document the exception. Keep the settings only where strictly necessary and ensure those pods are constrained (e.g., dedicated namespace, RBAC, NetworkPolicies).

        6. Verify all non-system pods are compliant (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pods --all-namespaces -o json | jq -r '
             [ .items[]
             | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
             | .metadata as $m
             | (.spec.hostPID // false) as $hostPID
             | (.spec.hostIPC // false) as $hostIPC
             | (.spec.hostNetwork // false) as $hostNet
             | "ns=\($m.namespace) name=\($m.name) hostPID=\($hostPID) hostIPC=\($hostIPC) hostNetwork=\($hostNet)"
               + " is_compliant=\(if ($hostPID or $hostIPC or $hostNet) then "false" else "true" end)"
             ] as $rows
             | if ($rows | map(select(. | contains("is_compliant=false"))) | length) == 0
               then "is_compliant=true"
               else $rows[]
               end'
           ```
           The cluster is compliant when the output is `is_compliant=true` and no rows show `is_compliant=false`.
      </Accordion>

      <Accordion title="Using kubectl">
        On any machine with kubectl access:

        1. Identify non-compliant pods (excluding AKS system namespaces):

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | jq -r '
          [ .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (.spec.hostPID // false) as $hostPID
          | (.spec.hostIPC // false) as $hostIPC
          | (.spec.hostNetwork // false) as $hostNet
          | select($hostPID or $hostIPC or $hostNet)
          | "ns=\($m.namespace) name=\($m.name)"
          ][]'
        ```

        2. For each listed pod, edit its controller (Deployment, StatefulSet, DaemonSet, Job, CronJob) so the template does not set host namespaces. Example for a Deployment:

        ```bash theme={null}
        kubectl -n <namespace> edit deployment <deployment-name>
        ```

        In the opened manifest, within `spec.template.spec`, ensure these fields are either removed or explicitly set to false:

        ```yaml theme={null}
        spec:
          template:
            spec:
              hostPID: false
              hostIPC: false
              hostNetwork: false
        ```

        Save and exit; Kubernetes will roll out updated pods.

        If the pod is a standalone Pod (no controller), replace it with a compliant manifest:

        ```bash theme={null}
        kubectl -n <namespace> get pod <pod-name> -o yaml > /tmp/pod-fixed.yaml
        ```

        Edit `/tmp/pod-fixed.yaml`:

        * Remove status fields and metadata fields that block creation (resourceVersion, uid, managedFields, etc.).
        * Under `spec`, set or remove host namespace fields:

        ```yaml theme={null}
        spec:
          hostPID: false
          hostIPC: false
          hostNetwork: false
        ```

        Delete and recreate:

        ```bash theme={null}
        kubectl -n <namespace> delete pod <pod-name>
        kubectl apply -f /tmp/pod-fixed.yaml
        ```

        3. Verification (same machine with kubectl):

        ```bash theme={null}
        kubectl get pods --all-namespaces -o json | jq -r '
          [ .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (.spec.hostPID // false) as $hostPID
          | (.spec.hostIPC // false) as $hostIPC
          | (.spec.hostNetwork // false) as $hostNet
          | select($hostPID or $hostIPC or $hostNet)
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediate pods that share host namespaces (hostPID/hostIPC/hostNetwork)
        # Target: any machine with kubectl access to the AKS cluster
        #
        # Requirements:
        #   - kubectl configured to talk to the cluster
        #   - jq installed
        #
        # This script:
        #   1. Identifies non-system pods with hostPID/hostIPC/hostNetwork = true
        #   2. Patches supported controllers (Deployment/StatefulSet/DaemonSet/ReplicaSet/Job/CronJob)
        #      to set these fields to false (or remove them).
        #   3. Reports pods that cannot be auto-fixed (e.g. naked Pods, custom controllers).
        #   4. Re-runs the audit at the end.

        set -euo pipefail

        echo "=== Detecting non-compliant pods (excluding kube-system, kube-public, kube-node-lease) ==="

        NON_COMPLIANT_JSON="$(kubectl get pods --all-namespaces -o json | jq -c '
          .items[]
          | select(.metadata.namespace as $n
                   | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | (.spec.hostPID // false) as $hostPID
          | (.spec.hostIPC // false) as $hostIPC
          | (.spec.hostNetwork // false) as $hostNet
          | select($hostPID or $hostIPC or $hostNet)
        ')"

        if [[ -z "${NON_COMPLIANT_JSON}" ]]; then
          echo "No non-compliant pods found. Cluster already compliant."
        else
          echo "Found non-compliant pods:"
          echo "${NON_COMPLIANT_JSON}" | jq -r '.metadata.namespace + "/" + .metadata.name + " hostPID=" + ((.spec.hostPID // false)|tostring) + " hostIPC=" + ((.spec.hostIPC // false)|tostring) + " hostNetwork=" + ((.spec.hostNetwork // false)|tostring)'
        fi

        echo
        echo "=== Identifying owning controllers for non-compliant pods ==="

        # Helper function: create a JSON patch that unsets/removes host* fields
        make_patch() {
          jq -n '
            {
              "spec": {
                "template": {
                  "spec": {}
                }
              }
            }
            | .spec.template.spec.hostPID = false
            | .spec.template.spec.hostIPC = false
            | .spec.template.spec.hostNetwork = false
          '
        }

        # Store patch in a variable for reuse
        PATCH_JSON="$(make_patch)"

        CONTROLLERS_PATCHED=()
        PODS_MANUAL_REVIEW=()

        # Process each non-compliant pod and patch its owning controller if possible
        if [[ -n "${NON_COMPLIANT_JSON}" ]]; then
          while IFS= read -r pod; do
            ns="$(jq -r '.metadata.namespace' <<<"${pod}")"
            pod_name="$(jq -r '.metadata.name' <<<"${pod}")"

            owner_kind="$(jq -r '([(.metadata.ownerReferences // [])[] | select(.controller)] | first | .kind) // ""' <<<"${pod}")"
            owner_name="$(jq -r '([(.metadata.ownerReferences // [])[] | select(.controller)] | first | .name) // ""' <<<"${pod}")"

            if [[ -z "${owner_kind}" || -z "${owner_name}" ]]; then
              PODS_MANUAL_REVIEW+=("${ns}/${pod_name} (no controller owner; likely a naked Pod)")
              continue
            fi

            # Map supported controller kinds to their resource types
            case "${owner_kind}" in
              Deployment|StatefulSet|DaemonSet|ReplicaSet|Job)
                resource="${owner_kind,,}s"   # lowercase + plural
                api_version="apps/v1"
                ;;
              CronJob)
                resource="cronjobs"
                api_version="batch/v1"
                ;;
              *)
                PODS_MANUAL_REVIEW+=("${ns}/${pod_name} (unsupported owner kind: ${owner_kind}; manual review)")
                continue
                ;;
            esac

            controller_key="${ns}/${resource}/${owner_name}"

            # Avoid patching the same controller multiple times
            if printf '%s\n' "${CONTROLLERS_PATCHED[@]:-}" | grep -qx -- "${controller_key}"; then
              continue
            fi

            echo
            echo "Patching ${owner_kind} ${ns}/${owner_name} to disable hostPID/hostIPC/hostNetwork..."

            # Apply JSON patch (strategic merge)
            kubectl -n "${ns}" patch "${resource}.${api_version}" "${owner_name}" \
              --type merge \
              -p "${PATCH_JSON}"

            CONTROLLERS_PATCHED+=("${controller_key}")
          done <<<"${NON_COMPLIANT_JSON}"
        fi

        echo
        echo "=== Summary of automated changes ==="
        if [[ ${#CONTROLLERS_PATCHED[@]} -eq 0 ]]; then
          echo "No controllers were patched (none found or all require manual review)."
        else
          printf 'Patched controllers:\n'
          printf '  %s\n' "${CONTROLLERS_PATCHED[@]}"
        fi

        if [[ ${#PODS_MANUAL_REVIEW[@]} -gt 0 ]]; then
          echo
          echo "The following pods require manual review (e.g., standalone Pods, custom controllers):"
          printf '  %s\n' "${PODS_MANUAL_REVIEW[@]}"
          echo "For each, update the owning manifest so that spec.hostPID/spec.hostIPC/spec.hostNetwork are omitted or set to false."
        fi

        echo
        echo "=== Waiting for pods to roll out after controller patches ==="
        # Give the cluster a bit of time to recreate pods; this is best-effort.
        sleep 10

        echo
        echo "=== Re-running compliance audit ==="
        kubectl get pods --all-namespaces -o json | jq -r '
          [ .items[]
          | select(.metadata.namespace as $n | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
          | .metadata as $m
          | (.spec.nodeName // "") as $node
          | (($m.labels // {}) | to_entries | map("\(.key):\(.value)") | join(",")) as $labels
          | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
          | (.spec.hostPID // false) as $hostPID
          | (.spec.hostIPC // false) as $hostIPC
          | (.spec.hostNetwork // false) as $hostNet
          | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
            + (if ($m.creationTimestamp // "") == "" then "" else " created=\($m.creationTimestamp)" end)
            + (if $node   == ""   then "" else " node=\($node)" end)
            + (if $labels == ""   then "" else " labels=\($labels)" end)
            + (if $own    == null then "" else " owner=\($own.kind)/\($m.namespace)/\($own.name)/\($own.uid)" end)
            + " hostPID=\($hostPID) hostIPC=\($hostIPC) hostNetwork=\($hostNet)"
            + " is_compliant=\(if ($hostPID or $hostIPC or $hostNet) then "false" else "true" end)"
          ] as $rows
          | if ($rows | length) == 0 then "is_compliant=true" else $rows[] end'
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
