> ## 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. Identify non-compliant pods (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' \
             | grep 'is_compliant=false'
           ```

        2. For each non-compliant pod, determine its owner (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl get pod POD_NAME -n POD_NAMESPACE -o jsonpath='{.metadata.ownerReferences[*].kind}{" "}{.metadata.ownerReferences[*].name}{"\n"}'
           ```
           * If there is no ownerReference, the Pod is standalone and must be fixed directly.
           * If there is an owner (Deployment, DaemonSet, StatefulSet, Job, etc.), you must edit that owner resource instead of the Pod.

        3. Edit the owning workload (preferred) to remove host namespace sharing (run on any machine with kubectl access):
           ```bash theme={null}
           kubectl -n POD_NAMESPACE edit DEPLOYMENT_OR_DAEMONSET_NAME
           ```
           In the opened manifest:
           * Locate `.spec.template.spec.hostPID`, `.spec.template.spec.hostIPC`, and `.spec.template.spec.hostNetwork`.
           * Set each present field to `false`:
             ```yaml theme={null}
             spec:
               template:
                 spec:
                   hostPID: false
                   hostIPC: false
                   hostNetwork: false
             ```
             or delete the lines entirely so they are omitted.
             Save and exit; Kubernetes will recreate pods from this workload. Be aware this may restart application pods and briefly disrupt traffic.

        4. If the Pod is standalone (no controller), edit or recreate it from a manifest (run on any machine with kubectl access):
           * If you have a manifest in version control, update it so the pod spec does not set these fields (omit them or set to `false`):
             ```yaml theme={null}
             spec:
               hostPID: false
               hostIPC: false
               hostNetwork: false
             ```
             Then:
             ```bash theme={null}
             kubectl apply -f PATH_TO_UPDATED_MANIFEST.yaml
             ```
           * If there is no manifest, export, edit, and re-create:
             ```bash theme={null}
             kubectl get pod POD_NAME -n POD_NAMESPACE -o yaml > /tmp/pod-fixed.yaml
             sed -i '/hostPID:/d;/hostIPC:/d;/hostNetwork:/d' /tmp/pod-fixed.yaml
             # remove runtime-only fields
             sed -i '/^  resourceVersion:/d;/^  uid:/d;/^  creationTimestamp:/d;/^  selfLink:/d;/^  managedFields:/,/^[^ ]/d' /tmp/pod-fixed.yaml
             sed -i '/status:/,$d' /tmp/pod-fixed.yaml
             kubectl delete pod POD_NAME -n POD_NAMESPACE
             kubectl apply -f /tmp/pod-fixed.yaml
             ```
             This will delete and recreate the pod; expect a restart and potential brief downtime.

        5. Repeat steps 2–4 for all pods reported as `is_compliant=false`, ensuring all updated specs have `hostPID`, `hostIPC`, and `hostNetwork` either omitted or explicitly set to `false`.

        6. Verify remediation (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'
           ```
           Confirm the output is `is_compliant=true` and that no lines show `is_compliant=false`.
      </Accordion>

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

        1. Identify offending pods and their controllers (exclude system namespaces per the audit):

        ```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
          | ([ ($m.ownerReferences // [])[] | select(.controller) ] | first) as $own
          | (.spec.hostPID // false) as $hostPID
          | (.spec.hostIPC // false) as $hostIPC
          | (.spec.hostNetwork // false) as $hostNet
          | select($hostPID or $hostIPC or $hostNet)
          | "\($m.namespace) \($m.name) \((if $own == null then "Pod" else $own.kind end))"
          ][]'
        ```

        2. For each owning controller (Deployment, DaemonSet, StatefulSet, Job, CronJob, or bare Pod), export its manifest:

        ```bash theme={null}
        # Example for a Deployment
        kubectl get deployment <deployment-name> -n <namespace> -o yaml > /tmp/<deployment-name>.yaml
        ```

        3. Edit the manifest to remove or explicitly set the host namespace fields under `spec.template.spec` (or `spec` for a bare Pod):

        ```yaml theme={null}
        spec:
          template:
            spec:
              # Remove these if present, or set them to false:
              hostPID: false
              hostIPC: false
              hostNetwork: false
        ```

        For bare Pods (not managed by a controller):

        ```yaml theme={null}
        spec:
          # Remove these if present, or set them to false:
          hostPID: false
          hostIPC: false
          hostNetwork: false
        ```

        4. Apply the updated manifest:

        ```bash theme={null}
        kubectl apply -f /tmp/<deployment-name>.yaml
        ```

        If you had to delete and recreate a bare Pod:

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

        5. Verification (re-run the audit and confirm all non-system pods are `is_compliant=true`):

        ```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
          | "kind=Pod ns=\($m.namespace) name=\($m.name) uid=\($m.uid) apiVersion=v1"
            + " 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: Ensure pods do not share host namespaces (hostPID/hostIPC/hostNetwork)
        # Scope: Any machine with kubectl access to the OKE cluster
        #
        # Behavior:
        # - Scans all namespaces except kube-system, kube-public, kube-node-lease
        # - For pods with hostPID/hostIPC/hostNetwork == true:
        #     * If controlled by a workload (Deployment/DaemonSet/StatefulSet/ReplicaSet/Job/CronJob):
        #         - Patch the controller’s pod template to set those fields to false
        #         - Delete the non-compliant pods so the controller recreates them
        #     * If not controlled by a workload:
        #         - Patches the pod in place to set those fields to false
        # - Safe to re-run: patches are idempotent; deleting managed pods lets controllers reconcile
        # - Verifies compliance at the end using the authoritative audit command

        set -euo pipefail

        # REQUIREMENTS:
        # - kubectl configured to point at the target OKE cluster
        # - jq installed

        # Helper: run kubectl with stable output (no colors, etc.)
        k() {
          kubectl "$@"
        }

        echo "Scanning for non-compliant pods (sharing host namespaces)..."

        NON_COMPLIANT_JSON=$(k get pods --all-namespaces -o json \
          | jq '
            .items[]
            | select(.metadata.namespace as $n
                     | ["kube-system","kube-public","kube-node-lease"] | index($n) | not)
            | . as $pod
            | (.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 "Non-compliant pods detected. Applying fixes..."

          # Process each non-compliant pod
          echo "${NON_COMPLIANT_JSON}" | jq -c '.' | while read -r POD_JSON; do
            NS=$(jq -r '.metadata.namespace' <<< "${POD_JSON}")
            NAME=$(jq -r '.metadata.name' <<< "${POD_JSON}")

            HOSTPID=$(jq -r '(.spec.hostPID // false) | tostring' <<< "${POD_JSON}")
            HOSTIPC=$(jq -r '(.spec.hostIPC // false) | tostring' <<< "${POD_JSON}")
            HOSTNET=$(jq -r '(.spec.hostNetwork // false) | tostring' <<< "${POD_JSON}")

            echo "Processing pod ${NS}/${NAME} (hostPID=${HOSTPID}, hostIPC=${HOSTIPC}, hostNetwork=${HOSTNET})"

            # Detect controlling ownerReference (if any)
            OWNER_KIND=$(jq -r '[.metadata.ownerReferences // [] | .[] | select(.controller)] | first.kind // ""' <<< "${POD_JSON}")
            OWNER_NAME=$(jq -r '[.metadata.ownerReferences // [] | .[] | select(.controller)] | first.name // ""' <<< "${POD_JSON}")

            # Patch payload to disable host namespaces
            PATCH='{"spec":{"hostPID":false,"hostIPC":false,"hostNetwork":false}}'

            if [[ -n "${OWNER_KIND}" && -n "${OWNER_NAME}" ]]; then
              echo "  -> Pod is controlled by ${OWNER_KIND}/${OWNER_NAME}. Patching controller template."

              # Determine patch path depending on controller kind
              case "${OWNER_KIND}" in
                Deployment|StatefulSet|DaemonSet|ReplicaSet)
                  TEMPLATE_PATH="spec.template.spec"
                  ;;
                Job)
                  TEMPLATE_PATH="spec.template.spec"
                  ;;
                CronJob)
                  # For CronJob v1: spec.jobTemplate.spec.template.spec
                  TEMPLATE_PATH="spec.jobTemplate.spec.template.spec"
                  ;;
                *)
                  echo "  !! Unsupported owner kind ${OWNER_KIND}. Skipping controller patch; patching pod directly."
                  TEMPLATE_PATH=""
                  ;;
              esac

              if [[ -n "${TEMPLATE_PATH}" ]]; then
                # Build a strategic merge patch targeting the pod template
                CONTROLLER_PATCH=$(jq -n --arg path "${TEMPLATE_PATH}" '
                  ($path | split(".") ) as $p
                  | {"spec":{}} as $obj
                  | reduce range(0; ($p|length)) as $i (
                      $obj;
                      if $i == 0 then
                        .[$p[$i]] //= {}
                      elif $i == ($p|length - 1) then
                        path($p) |= . + {"hostPID":false,"hostIPC":false,"hostNetwork":false}
                      else
                        path($p[0:$i+1]) //= {}
                      end
                    )
                ')

                echo "  -> Patching ${OWNER_KIND}/${NS}/${OWNER_NAME}..."
                k -n "${NS}" patch "${OWNER_KIND,,}" "${OWNER_NAME}" --type=merge -p "${CONTROLLER_PATCH}" >/dev/null

                echo "  -> Deleting non-compliant pod so controller recreates it..."
                k -n "${NS}" delete pod "${NAME}" --wait=false >/dev/null || true
              else
                echo "  -> Patching pod ${NS}/${NAME} directly..."
                k -n "${NS}" patch pod "${NAME}" --type=merge -p "${PATCH}" >/dev/null || true
              fi
            else
              echo "  -> Pod has no controlling owner. Patching pod directly."
              k -n "${NS}" patch pod "${NAME}" --type=merge -p "${PATCH}" >/dev/null || true
            fi
          done
        fi

        echo "Verification: re-running compliance check..."

        k 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 | map(select(. | contains("is_compliant=false"))) | length) == 0
            then "is_compliant=true"
            else $rows[]
            end
        '
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
