Skip to main content

Minimize The Admission Of Containers Sharing The Host IPC

More Info:

Sharing the host IPC namespace exposes host inter-process communication to the container. Restrict hostIPC pods in workload namespaces.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Identify pods using hostIPC (any machine with kubectl access):

    kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.hostIPC==true)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
  2. For each affected pod, retrieve its owning controller (Deployment/StatefulSet/DaemonSet/Job) if any (any kubectl machine):

    NAMESPACE=example-namespace
    POD=example-pod
    kubectl get pod "$POD" -n "$NAMESPACE" -o jsonpath='{.metadata.ownerReferences}' | jq

    If there is an ownerReference, plan to edit the controller; otherwise plan to edit the Pod manifest source (e.g., Helm chart, YAML in Git).

  3. Create or update a PodSecurity admission policy to deny hostIPC in workload namespaces (any kubectl machine; example for namespace team-a using Pod Security Standards via namespace labels):

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

    The restricted profile forbids hostIPC: true in new or updated pods.

  4. For clusters without Pod Security Admission (or if you prefer Kyverno), create a policy manifest to block hostIPC (any kubectl machine). Example Kyverno ClusterPolicy:

    cat > deny-hostipc.yaml << 'EOF'
    apiVersion: kyverno.io/v1
    kind: ClusterPolicy
    metadata:
    name: disallow-host-ipc
    spec:
    validationFailureAction: Enforce
    background: true
    rules:
    - name: deny-host-ipc
    match:
    any:
    - resources:
    kinds:
    - Pod
    validate:
    message: "Using hostIPC is not allowed."
    pattern:
    spec:
    hostIPC: "false"
    EOF

    kubectl apply -f deny-hostipc.yaml

    Adjust the policy or use your preferred admission controller (e.g., OPA/Gatekeeper) and scope it only to user workload namespaces as per your cluster design.

  5. Remove hostIPC: true from workload definitions (any kubectl machine, editing the actual source manifests/Helm values; example for a Deployment):

    kubectl get deployment my-app -n team-a -o yaml > /tmp/my-app-deploy.yaml
    sed -i '/hostIPC: true/d' /tmp/my-app-deploy.yaml
    kubectl apply -f /tmp/my-app-deploy.yaml

    For pods directly created from YAML:

    kubectl get pod example-pod -n team-a -o yaml > /tmp/example-pod.yaml
    sed -i '/hostIPC: true/d' /tmp/example-pod.yaml
    kubectl delete pod example-pod -n team-a
    kubectl apply -f /tmp/example-pod.yaml

    Review with application owners before removing hostIPC in case it is functionally required; if truly required, document and tightly scope exceptions in the admission policy.

  6. Verification (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_hostipc=$(kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o jsonpath='{.spec.hostIPC}' 2>/dev/null)
    if [ -z "${pod_hostipc}" ]; then
    pod_hostipc="false"
    echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostipc: ${pod_hostipc} is_compliant: true"
    else
    echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostipc: ${pod_hostipc} is_compliant: false"
    fi
    done

    Confirm that no output lines show is_pod_hostipc: true is_compliant: false in user workload namespaces.

Using kubectl
# 1) Create a baseline PodSecurityPolicy that forbids hostIPC
# (only if your cluster still uses PodSecurityPolicy)
# Run on: any machine with kubectl access
cat << 'EOF' | kubectl apply -f -
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-no-hostipc
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
spec:
privileged: false
hostIPC: false
hostNetwork: false
hostPID: false
hostPorts: []
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
volumes:
- 'configMap'
- 'downwardAPI'
- 'emptyDir'
- 'persistentVolumeClaim'
- 'projected'
- 'secret'
EOF
# 2) Bind the PSP to workload namespaces (example: "apps" and "dev")
# Adjust the namespace list as needed.
# Run on: any machine with kubectl access

# Create a ClusterRole that can use the restricted PSP
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind ClusterRole
metadata:
name: use-restricted-no-hostipc-psp
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['restricted-no-hostipc']
EOF
# Bind the above ClusterRole to all serviceaccounts in a namespace
# Repeat (or template) for each workload namespace

# Example for namespace "apps"
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: use-restricted-no-hostipc-psp
namespace: apps
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: use-restricted-no-hostipc-psp
subjects:
- kind: Group
name: system:serviceaccounts:apps
apiGroup: rbac.authorization.k8s.io
EOF
# Example for namespace "dev"
cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: use-restricted-no-hostipc-psp
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: use-restricted-no-hostipc-psp
subjects:
- kind: Group
name: system:serviceaccounts:dev
apiGroup: rbac.authorization.k8s.io
EOF
# 3) (Alternative / modern clusters) Enforce the Pod Security "restricted" profile,
# which also disallows hostIPC, on workload namespaces via Pod Security Admission.
# This does not require PSP and is the recommended approach on new clusters.

# Example for namespace "apps"
kubectl label namespace apps \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
--overwrite

# Example for namespace "dev"
kubectl label namespace dev \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
--overwrite
# 4) Remove hostIPC from existing Pod specs that use it (if any).
# For each non-system namespace, inspect and patch.

# List pods currently using hostIPC=true
kubectl get pods --all-namespaces -o json | \
jq -r '.items[] | select(.spec.hostIPC==true) | "\(.metadata.namespace) \(.metadata.name)"'

# For each pod found above, edit its controller (Deployment/StatefulSet/DaemonSet/Job)
# and remove "hostIPC: true" from the pod spec. Example:

# Example for Deployment "web" in namespace "apps"
kubectl -n apps edit deploy web
# (In the editor, delete the line "hostIPC: true" under spec.template.spec and save.)

# If it's a bare Pod (no controller), delete and recreate it from a corrected manifest:
kubectl -n apps delete pod <pod-name>
# then apply a manifest that omits hostIPC.
# 5) Verification: confirm that no running pod has spec.hostIPC=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_hostipc=$(kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o jsonpath='{.spec.hostIPC}' 2>/dev/null)
if [ -z "${pod_hostipc}" ]; then
pod_hostipc="false"
fi
echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostipc: ${pod_hostipc} is_compliant: $([ "${pod_hostipc}" = "false" ] && echo true || echo false)"
done
Automation
#!/usr/bin/env bash
#
# Purpose:
# Minimize admission of pods using hostIPC by:
# - Creating a baseline "deny-hostipc" Pod Security Policy (for PSP clusters)
# - Creating a "restricted-hostipc" Pod Security Policy (or namespace labels)
# - Labeling workload namespaces so that hostIPC is disallowed by default
#
# Scope:
# - Runs from any machine with kubectl access and appropriate RBAC.
# - Idempotent and safe to re-run.
#
# Notes:
# - This check is MANUAL; this script implements one reasonable, restrictive pattern.
# - You should review namespaces that are excluded from restriction (system namespaces).
# - If your cluster does NOT support PodSecurityPolicy (PSP), the script will fall back
# to Kubernetes Pod Security Admission labels (restricted profile) to prevent hostIPC.

set -euo pipefail

# -------- Configuration (edit as needed) --------

# Namespaces to IGNORE (no hostIPC restrictions applied here by this script)
IGNORED_NAMESPACES=(
"kube-system"
"kube-public"
"kube-node-lease"
"default" # remove "default" here if you want to restrict it as well
)

# Label key used for workload namespaces to mark them as restricted.
WORKLOAD_LABEL_KEY="security.k8s.io/hostipc-restricted"
WORKLOAD_LABEL_VALUE="true"

# PSP names (if PSP API is present)
PSP_BASELINE_NAME="baseline-deny-hostipc"
PSP_RESTRICTED_NAME="restricted-deny-hostipc"

# -------- Helper functions --------

ns_in_ignored_list() {
local ns="$1"
for ignored in "${IGNORED_NAMESPACES[@]}"; do
if [[ "$ignored" == "$ns" ]]; then
return 0
fi
done
return 1
}

kubectl_api_exists() {
local api="$1"
if kubectl api-versions | grep -q "^${api}"; then
return 0
fi
return 1
}

# -------- Detect PSP support and Pod Security Admission --------

echo "[INFO] Detecting PodSecurityPolicy (PSP) support..."
PSP_SUPPORTED=false
if kubectl_api_exists "policy/v1beta1"; then
if kubectl api-resources | awk '{print $1}' | grep -qx "podsecuritypolicies"; then
PSP_SUPPORTED=true
echo "[INFO] PSP is supported by this cluster."
fi
fi

echo "[INFO] Detecting Pod Security Admission support (Pod Security Standards labels)..."
PSA_SUPPORTED=false
if kubectl_api_exists "policy/v1"; then
PSA_SUPPORTED=true
echo "[INFO] policy/v1 is present; assuming Pod Security Admission is enabled or available."
fi

if [[ "$PSP_SUPPORTED" == "false" && "$PSA_SUPPORTED" == "false" ]]; then
echo "[WARN] Neither PodSecurityPolicy nor Pod Security Admission (PSS labels) could be confirmed."
echo "[WARN] This script cannot enforce hostIPC restrictions automatically in this cluster."
echo "[WARN] Please refer to the Manual Steps section for alternative enforcement (e.g., OPA/Gatekeeper or Kyverno)."
exit 0
fi

# -------- PSP-based approach (if available) --------

if [[ "$PSP_SUPPORTED" == "true" ]]; then
echo "[INFO] Applying PSP-based hostIPC restrictions."

# 1. Create or update a baseline PSP that denies hostIPC
cat <<EOF | kubectl apply -f -
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: ${PSP_BASELINE_NAME}
spec:
privileged: false
hostIPC: false
hostNetwork: false
hostPID: false
seLinux:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
EOF

# 2. Create or update a stricter PSP for workload namespaces that denies hostIPC
cat <<EOF | kubectl apply -f -
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: ${PSP_RESTRICTED_NAME}
spec:
privileged: false
hostIPC: false
hostNetwork: false
hostPID: false
seLinux:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
EOF

echo "[INFO] PSPs ${PSP_BASELINE_NAME} and ${PSP_RESTRICTED_NAME} have been applied."

# Note:
# Binding these PSPs to users/service accounts is cluster-specific RBAC work and is not
# deterministically automatable here. You MUST ensure that:
# - Workload namespaces / service accounts only have access to PSPs with hostIPC=false.
# Use Manual Steps guidance to finalize RBAC bindings.

fi

# -------- Pod Security Admission label-based approach --------

if [[ "$PSA_SUPPORTED" == "true" ]]; then
echo "[INFO] Applying Pod Security Admission labels to restrict hostIPC in workload namespaces."

# Retrieve all namespaces except the ignored ones
ALL_NAMESPACES=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
for ns in $ALL_NAMESPACES; do
if ns_in_ignored_list "$ns"; then
echo "[INFO] Skipping ignored namespace: $ns"
continue
fi

echo "[INFO] Labeling namespace $ns for restricted pod security profile and hostIPC restriction."

# Apply restricted PodSecurity labels (if not already present)
# These labels ensure that pods cannot use hostIPC or other host namespaces by default.
kubectl label namespace "$ns" \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
--overwrite

# Additional marker label for tracking that this namespace is intended to disallow hostIPC
kubectl label namespace "$ns" \
"${WORKLOAD_LABEL_KEY}=${WORKLOAD_LABEL_VALUE}" \
--overwrite
done
fi

# -------- Verification --------

echo "[INFO] Verifying that no running pods use hostIPC=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_hostipc=$(kubectl get pod "${pod_name}" --namespace "${pod_namespace}" -o jsonpath='{.spec.hostIPC}' 2>/dev/null || true)
if [ -z "${pod_hostipc}" ]; then
pod_hostipc="false"
echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostipc: ${pod_hostipc} is_compliant: true"
else
echo "***pod_name: ${pod_name} pod_namespace: ${pod_namespace} is_pod_hostipc: ${pod_hostipc} is_compliant: false"
fi
done

echo "[INFO] Verification complete. Review any lines with is_compliant: false."