> ## 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 any 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.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) hostPID=\($hostPID) hostIPC=\($hostIPC) hostNetwork=\($hostNet)"
             ][]'
           ```

        2. For each offending pod, identify its controller (Deployment/DaemonSet/StatefulSet/Job/etc.) and namespace (run on any machine with kubectl access; replace NAMESPACE and POD\_NAME):
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.ownerReferences}'
           ```
           If empty, the pod is standalone and must be deleted and recreated from a corrected manifest.

        3. Edit the owning workload to remove host namespace sharing (run on any machine with kubectl access; choose the correct kind and set NAMESPACE/NAME):
           ```bash theme={null}
           # Example for a Deployment
           kubectl edit deployment NAME -n NAMESPACE
           ```
           In the editor, under `spec.template.spec`, ensure these fields are either removed or explicitly set to false:
           ```yaml theme={null}
           spec:
             template:
               spec:
                 hostPID: false      # or remove this line
                 hostIPC: false      # or remove this line
                 hostNetwork: false  # or remove this line
           ```
           Save and exit; Kubernetes will roll out updated pods.

        4. For standalone pods not managed by a controller (run on any machine with kubectl access; replace NAMESPACE and POD\_NAME):
           ```bash theme={null}
           kubectl get pod POD_NAME -n NAMESPACE -o yaml > /tmp/pod-POD_NAME.yaml
           ```
           Edit `/tmp/pod-POD_NAME.yaml` and under `spec` remove `hostPID`, `hostIPC`, and `hostNetwork` or set them to `false`. Also remove `metadata.resourceVersion`, `metadata.uid`, `metadata.creationTimestamp`, `metadata.managedFields`, `status`, and any `ownerReferences`. Then recreate:
           ```bash theme={null}
           kubectl delete pod POD_NAME -n NAMESPACE
           kubectl apply -f /tmp/pod-POD_NAME.yaml
           ```

        5. Repeat steps 2–4 for each non-compliant pod until all workloads have `hostPID`, `hostIPC`, and `hostNetwork` omitted or set to `false` in their pod specs.

        6. Verify no remaining non-system pods share host namespaces (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(. | test("is_compliant=false"))) | length) == 0
               then "is_compliant=true"
               else $rows[]
               end'
           ```
      </Accordion>

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

        1. Identify all pods using host namespaces (excluding core namespaces, as per the audit):

        ```sh 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, edit its controller manifest (Deployment, StatefulSet, DaemonSet, Job, etc.) to ensure `hostPID`, `hostIPC`, and `hostNetwork` are not set to true.

        Example: patch a Deployment to explicitly disable them:

        ```sh theme={null}
        kubectl patch deployment <deployment-name> \
          -n <namespace> \
          --type merge \
          -p '{
            "spec": {
              "template": {
                "spec": {
                  "hostPID": false,
                  "hostIPC": false,
                  "hostNetwork": false
                }
              }
            }
          }'
        ```

        Example: if the running pod is not controlled by a higher-level object (standalone Pod), export, modify, and re-apply:

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

        Edit `/tmp/pod-fixed.yaml` and in `spec` remove `hostPID`, `hostIPC`, and `hostNetwork` fields entirely, or set them to `false`:

        ```yaml theme={null}
        spec:
          # hostPID: true        # REMOVE
          # hostIPC: true        # REMOVE
          # hostNetwork: true    # REMOVE
          containers:
          - name: ...
            image: ...
        ```

        Delete and recreate the pod from the fixed manifest:

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

        Note: changing these fields causes pods to be recreated by their controllers, which may briefly disrupt workloads using host namespaces.

        3. Verification (on any machine with kubectl access):

        Re-run the audit command; it should now report `is_compliant=true` for all remaining rows or a single `is_compliant=true` line:

        ```sh 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'
        ```
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation for: Pods Should Not Share Host Namespaces (hostPID/hostIPC/hostNetwork)
        # Scope: GKE cluster, all namespaces except kube-system, kube-public, kube-node-lease
        # Requirements: kubectl, jq, yq (https://mikefarah.gitbook.io/yq/) installed on this machine
        # Safe to re-run: yes (only patches pods that request host namespaces)

        set -euo pipefail

        # --- configuration ---

        # Label key/value to mark non-compliant pods so controllers can be fixed by their owners.
        MARK_LABEL_KEY="security.host-namespaces"
        MARK_LABEL_VALUE="noncompliant"

        # --- functions ---

        need_bin() {
          if ! command -v "$1" >/dev/null 2>&1; then
            echo "ERROR: required binary '$1' not found in PATH" >&2
            exit 1
          fi
        }

        verify_cluster_access() {
          if ! kubectl version --request-timeout=10s >/dev/null 2>&1; then
            echo "ERROR: cannot talk to cluster with kubectl. Check kubeconfig/context." >&2
            exit 1
          fi
        }

        # List non-compliant pods (excluding control-plane/system namespaces)
        list_noncompliant_pods() {
          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)
            | select((.spec.hostPID // false) or (.spec.hostIPC // false) or (.spec.hostNetwork // false))
            | "\(.metadata.namespace) \(.metadata.name)"
          '
        }

        # Try to patch pod spec to disable host namespaces.
        # Note: For pods managed by controllers, the controller will usually recreate them with the same spec.
        # This script therefore ALSO tags such pods so owners can update the real manifests/IaC.
        patch_pod() {
          local ns="$1"
          local name="$2"

          echo "Processing pod ${ns}/${name} ..."

          # Get ownerReferences to see if this is a bare pod
          local owners
          owners="$(kubectl -n "${ns}" get pod "${name}" -o json | jq '.metadata.ownerReferences // []')"

          # Always label pod as noncompliant so it can be tracked
          kubectl -n "${ns}" label pod "${name}" \
            "${MARK_LABEL_KEY}=${MARK_LABEL_VALUE}" --overwrite >/dev/null

          if [ "${owners}" != "[]" ]; then
            echo "  -> Pod is controlled by a higher-level resource; not editing controller via this script."
            echo "     Marked with label ${MARK_LABEL_KEY}=${MARK_LABEL_VALUE}."
            return 0
          fi

          # For standalone pods, we can directly patch the pod spec and recreate it
          echo "  -> Pod has no controller; attempting safe reconciliation."

          # Export full manifest
          tmpdir="$(mktemp -d)"
          manifest="${tmpdir}/pod.yaml"
          new_manifest="${tmpdir}/pod-fixed.yaml"

          kubectl -n "${ns}" get pod "${name}" -o yaml > "${manifest}"

          # Remove fields that must not be set on create
          # and set hostPID/hostIPC/hostNetwork to false (or omit them).
          yq '
            del(.metadata.uid,
                .metadata.resourceVersion,
                .metadata.selfLink,
                .metadata.creationTimestamp,
                .metadata.generation,
                .metadata.managedFields,
                .metadata.annotations."kubectl.kubernetes.io/last-applied-configuration",
                .status)
            | .spec.hostPID = false
            | .spec.hostIPC = false
            | .spec.hostNetwork = false
          ' "${manifest}" > "${new_manifest}"

          echo "  -> Deleting original pod ${ns}/${name} ..."
          kubectl -n "${ns}" delete pod "${name}" --wait=true

          echo "  -> Recreating pod ${ns}/${name} without host namespaces ..."
          kubectl -n "${ns}" apply -f "${new_manifest}"

          rm -rf "${tmpdir}"
        }

        verify_compliance() {
          echo
          echo "=== Verification (should report is_compliant=true or only compliant pods) ==="
          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'
        }

        # --- main ---

        need_bin kubectl
        need_bin jq
        need_bin yq
        verify_cluster_access

        echo "Discovering non-compliant pods (using hostPID/hostIPC/hostNetwork) ..."
        mapfile -t pods < <(list_noncompliant_pods || true)

        if [ "${#pods[@]}" -eq 0 ]; then
          echo "No non-compliant pods found."
          verify_compliance
          exit 0
        fi

        echo "Found ${#pods[@]} non-compliant pod(s)."

        for line in "${pods[@]}"; do
          ns="$(echo "${line}" | awk '{print $1}')"
          name="$(echo "${line}" | awk '{print $2}')"
          patch_pod "${ns}" "${name}"
        done

        verify_compliance
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
