Skip to main content

Minimize Admission Containers Wishing Host IPC Namespace

More Info:​

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

Risk Level​

Critical

Address​

Security

Compliance Standards​

  • CIS Kubernetes

Triage and Remediation​

Remediation​

Manual Steps
  1. Identify pods currently using hostIPC (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 [ "${pod_hostipc}" = "true" ]; then
    echo "POD: ${pod_name} NAMESPACE: ${pod_namespace} hostIPC: true"
    fi
    done
  2. For each affected namespace, review whether any workload must legitimately use hostIPC (design/ops decision):

    • List pods and their controllers:
      kubectl get pods -n <NAMESPACE> -o wide
      kubectl get deploy,sts,ds,job,cronjob -n <NAMESPACE>
    • With application owners, decide whether hostIPC: true is strictly required; if not, plan to remove it and block future use.
  3. Remove hostIPC from existing workload specs (any machine with kubectl access):

    • For a Deployment (repeat for other controllers as needed):
      kubectl -n <NAMESPACE> get deploy <DEPLOYMENT_NAME> -o yaml > /tmp/deploy-no-hostipc.yaml
      Edit /tmp/deploy-no-hostipc.yaml and remove any line like:
      hostIPC: true
      from under spec.template.spec.
      • Apply the change:
        kubectl apply -f /tmp/deploy-no-hostipc.yaml
    • Repeat similarly for StatefulSets, DaemonSets, Jobs, and CronJobs in that namespace.
  4. Create or update a PodSecurityPolicy (if still in use in your cluster) or Pod Security admission configuration to disallow hostIPC in user namespaces (any machine with kubectl access):

    Example PodSecurityPolicy (if PSP enabled):

    cat >/tmp/psp-no-hostipc.yaml <<'EOF'
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
    name: disallow-hostipc
    spec:
    hostIPC: false
    privileged: false
    seLinux:
    rule: RunAsAny
    runAsUser:
    rule: RunAsAny
    fsGroup:
    rule: RunAsAny
    supplementalGroups:
    rule: RunAsAny
    volumes:
    - '*'
    EOF

    kubectl apply -f /tmp/psp-no-hostipc.yaml

    Then bind it to service accounts in user namespaces:

    cat >/tmp/psp-no-hostipc-rb.yaml <<'EOF'
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    name: use-psp-disallow-hostipc
    rules:
    - apiGroups: ["policy"]
    resources: ["podsecuritypolicies"]
    verbs: ["use"]
    resourceNames: ["disallow-hostipc"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
    name: use-psp-disallow-hostipc
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: use-psp-disallow-hostipc
    subjects:
    - kind: Group
    name: system:serviceaccounts
    apiGroup: rbac.authorization.k8s.io
    EOF

    kubectl apply -f /tmp/psp-no-hostipc-rb.yaml

    If you use the built-in Pod Security admission instead of PSP, ensure user namespaces are labeled with a policy level that forbids hostIPC (e.g. restricted), after reviewing impact:

    kubectl label namespace <NAMESPACE> pod-security.kubernetes.io/enforce=restricted --overwrite
  5. Test admission control behavior in a non-production namespace (any machine with kubectl access):

    kubectl create namespace hostipc-test
    kubectl label namespace hostipc-test pod-security.kubernetes.io/enforce=restricted --overwrite

    cat >/tmp/hostipc-test-pod.yaml <<'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
    name: hostipc-test-pod
    namespace: hostipc-test
    spec:
    hostIPC: true
    containers:
    - name: pause
    image: registry.k8s.io/pause:3.9
    EOF

    kubectl apply -f /tmp/hostipc-test-pod.yaml

    Confirm that admission is rejected (pod is not created and an error is returned). After testing, you may delete the test namespace:

    kubectl delete namespace hostipc-test
  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

    Review output and ensure no pods report is_pod_hostipc: true.

Using kubectl

On any machine with kubectl access:

  1. Identify namespaces with user workloads (example list; adjust to your environment):
kubectl get ns
  1. Create a restrictive PodSecurityPolicy (if PSP is enabled) or a validating policy via a policy engine (e.g., Kyverno, Gatekeeper). Below are example manifests you can adapt; choose the mechanism actually available in your cluster.

Example: Kyverno policy to block hostIPC pods​

Save as deny-hostipc-pods.yaml:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-hostipc
spec:
validationFailureAction: enforce
background: true
rules:
- name: check-hostipc
match:
any:
- resources:
kinds:
- Pod
namespaces:
- "default"
- "prod"
- "staging"
validate:
message: "Using hostIPC is not allowed in this namespace."
pattern:
spec:
=(hostIPC): "false"

Apply:

kubectl apply -f deny-hostipc-pods.yaml

Edit the namespaces list in the manifest to cover each namespace that hosts user workloads.

Example: Gatekeeper (OPA) ConstraintTemplate + Constraint​

Save as hostipc-template.yaml:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sdenydisallowedhostipc
spec:
crd:
spec:
names:
kind: K8sDenyDisallowedHostIPC
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdenydisallowedhostipc

violation[{"msg": msg}] {
input.review.kind.kind == "Pod"
hostipc := input.review.object.spec.hostIPC
hostipc == true
msg := "Using hostIPC is not allowed in this namespace."
}

Apply:

kubectl apply -f hostipc-template.yaml

Then create a constraint, e.g. hostipc-constraint.yaml:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyDisallowedHostIPC
metadata:
name: disallow-hostipc
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- "default"
- "prod"
- "staging"

Apply:

kubectl apply -f hostipc-constraint.yaml

Update the namespaces list as needed.

Example: PodSecurityPolicy (only if PSP is enabled)​

Save as psp-no-hostipc.yaml:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp-no-hostipc
spec:
privileged: false
hostIPC: false
seLinux:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'

Apply:

kubectl apply -f psp-no-hostipc.yaml

Then bind it per namespace (example for prod):

# file: psp-no-hostipc-rb-prod.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: use-psp-no-hostipc
namespace: prod
rules:
- apiGroups: ["policy"]
resources: ["podsecuritypolicies"]
resourceNames: ["psp-no-hostipc"]
verbs: ["use"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: use-psp-no-hostipc
namespace: prod
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: use-psp-no-hostipc
subjects:
- kind: Group
name: system:serviceaccounts:prod
apiGroup: rbac.authorization.k8s.io

Apply:

kubectl apply -f psp-no-hostipc-rb-prod.yaml

Repeat the Role/RoleBinding per namespace that hosts user workloads.

  1. Verification (re-run the provided audit):
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 no new pods with is_pod_hostipc: true can be created in the protected namespaces.

Automation
#!/usr/bin/env bash
# Purpose: Minimize admission of pods with hostIPC=true by applying a restrictive
# PodSecurityPolicy/PodSecurityStandard-style policy (via PodSecurity admission labels)
# to all user namespaces.
#
# Scope: Run on any machine with kubectl access and appropriate permissions.
# Idempotent: Safe to re-run; it only adds/updates labels and does not delete objects.
#
# NOTE:
# - This benchmark control is MANUAL: you must review workloads that truly need hostIPC.
# - This script focuses on *preventing new* hostIPC pods in user namespaces.
# - It does NOT modify or evict existing pods that already use hostIPC=true.

set -euo pipefail

# ------------- Configuration (EDIT IF NEEDED) ----------------

# Regex to identify system namespaces which should be excluded from enforcement
# (kube-system and similar). You can extend this list if needed.
SYSTEM_NS_REGEX='^(kube-system|kube-public|kube-node-lease|default)$'

# Desired Pod Security admission levels for user namespaces.
# 'restricted' denies hostIPC and other privileged features.
POD_SECURITY_ENFORCE_LEVEL="restricted"
POD_SECURITY_AUDIT_LEVEL="restricted"
POD_SECURITY_WARN_LEVEL="restricted"

# --------------------------------------------------------------

echo "[INFO] Verifying kubectl connectivity..."
kubectl version --short >/dev/null

echo "[INFO] Discovering namespaces..."
all_namespaces=$(kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')

user_namespaces=()
while IFS= read -r ns; do
if [[ ! "$ns" =~ $SYSTEM_NS_REGEX ]]; then
user_namespaces+=("$ns")
fi
done <<< "$all_namespaces"

if [ ${#user_namespaces[@]} -eq 0 ]; then
echo "[INFO] No user namespaces found (only system namespaces match). Nothing to do."
else
echo "[INFO] User namespaces to process:"
printf ' - %s\n' "${user_namespaces[@]}"
fi

# ------------- Apply restrictive PodSecurity labels -------------

for ns in "${user_namespaces[@]}"; do
echo "[INFO] Applying PodSecurity labels to namespace: $ns"

# Idempotent label application (add/update as needed)
kubectl label namespace "$ns" \
"pod-security.kubernetes.io/enforce=$POD_SECURITY_ENFORCE_LEVEL" \
"pod-security.kubernetes.io/audit=$POD_SECURITY_AUDIT_LEVEL" \
"pod-security.kubernetes.io/warn=$POD_SECURITY_WARN_LEVEL" \
--overwrite
done

# ------------- Manual review guidance for existing hostIPC pods -------------

echo "[INFO] Listing existing pods with hostIPC=true (for manual review)..."
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 [ -n "${pod_hostipc}" ] && [ "${pod_hostipc}" = "true" ]; then
echo " [WARNING] Existing hostIPC pod: ${pod_namespace}/${pod_name}"
fi
done || true

cat <<'EOF'

[NOTE] The control is MANUAL:
- Review each WARNING line above to determine if hostIPC=true is strictly necessary.
- For each workload where hostIPC is not required, update its Deployment/PodSpec to remove `hostIPC: true`.
- For workloads that truly require hostIPC, consider:
* Running them only in tightly controlled namespaces.
* Applying more targeted admission controls (e.g., admission webhook, Gatekeeper policies).

EOF

# ------------- Verification (adapted from audit) ----------------

echo "[INFO] Re-running audit to verify current state of hostIPC usage..."
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

Additional Reading:​