More Info:
Sharing the host IPC namespace exposes host inter-process communication to the container. Restrict hostIPC pods in workload namespaces.Risk Level
HighAddress
SecurityCompliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
Manual Steps
-
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}' -
For each affected pod, retrieve its owning controller (Deployment/StatefulSet/DaemonSet/Job) if any (any kubectl machine):
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).
NAMESPACE=example-namespace POD=example-pod kubectl get pod "$POD" -n "$NAMESPACE" -o jsonpath='{.metadata.ownerReferences}' | jq -
Create or update a PodSecurity admission policy to deny
hostIPCin workload namespaces (any kubectl machine; example for namespaceteam-ausing Pod Security Standards via namespace labels):Thekubectl label namespace team-a \ pod-security.kubernetes.io/enforce=restricted \ pod-security.kubernetes.io/enforce-version=latest \ --overwriterestrictedprofile forbidshostIPC: truein new or updated pods. -
For clusters without Pod Security Admission (or if you prefer Kyverno), create a policy manifest to block
hostIPC(any kubectl machine). Example Kyverno ClusterPolicy: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.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 -
Remove
hostIPC: truefrom workload definitions (any kubectl machine, editing the actual source manifests/Helm values; example for a Deployment):For pods directly created from YAML: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.yamlReview with application owners before removingkubectl 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.yamlhostIPCin case it is functionally required; if truly required, document and tightly scope exceptions in the admission policy. -
Verification (any machine with kubectl access):
Confirm that no output lines show
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 doneis_pod_hostipc: true is_compliant: falsein user workload namespaces.
Using kubectl
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
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."

