Minimize Admission Containers Wishing Share Host Process Id
More Info:
Do not generally permit containers to be run with the hostPID flag set to true.
Risk Level
High
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CIS EKS
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify namespaces with user workloads (on any machine with kubectl access):
kubectl get nsDecide which are “user workload” namespaces (exclude kube-system, kube-public, kube-node-lease, and provider/system namespaces unless you explicitly run workloads there).
-
Create a baseline policy manifest file locally (on any machine with kubectl access), e.g.
disallow-hostpid-policy.yaml, using either ValidatingAdmissionPolicy (Kubernetes ≥1.30 with Kubernetes-native admission) or Gatekeeper/PSP/OPA if already standardized in your environment. Example using a ValidatingAdmissionPolicy that denies hostPID in all non-exempt namespaces:apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata:name: deny-hostpidspec:failurePolicy: FailmatchConstraints:resourceRules:- apiGroups: [""]apiVersions: ["v1"]operations: ["CREATE", "UPDATE"]resources: ["pods"]matchConditions:- name: exclude-system-namespacesexpression: '!(object.metadata.namespace in ["kube-system","kube-public","kube-node-lease"])'validations:- expression: '!(object.spec.hostPID == true)'message: "Pods must not be created with hostPID: true"---apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata:name: deny-hostpid-bindingspec:policyName: deny-hostpidvalidationActions: ["Deny"] -
Review and, if needed, adjust the namespace exclusion list and scope (on any machine with kubectl access), for example by changing
exclude-system-namespacesto also exclude any operational namespaces where hostPID is required, or by narrowing the policy to a label selector if you only want to enforce it on specific user namespaces. -
Apply the policy to the cluster (on any machine with kubectl access):
kubectl apply -f disallow-hostpid-policy.yaml -
Test that hostPID pods are now blocked in at least one user namespace (on any machine with kubectl access), replacing
user-namespacewith a real namespace:cat << 'EOF' | kubectl apply -f -apiVersion: v1kind: Podmetadata:name: hostpid-test-denynamespace: user-namespacespec:hostPID: truecontainers:- name: sleepimage: busybox:1.36command: ["sleep", "3600"]EOFConfirm that creation is rejected with a validation/admission error.
-
Verify that no pods with
hostPID: trueremain (on any machine with kubectl access):kubectl get pods --all-namespaces -o json | \jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end'
Using kubectl
# Apply this to each namespace that runs user workloads (edit metadata.name).
# Example for namespace "apps":
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: disallow-hostpid
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
spec:
privileged: false
hostPID: false
hostIPC: false
hostNetwork: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: disallow-hostpid-psp-user
namespace: apps
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames: ['disallow-hostpid']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: disallow-hostpid-psp-binding
namespace: apps
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: disallow-hostpid-psp-user
subjects:
# Adjust to your user/groups/serviceaccounts that run workloads in this namespace
- kind: Group
name: system:serviceaccounts:apps
apiGroup: rbac.authorization.k8s.io
Apply the policy
Run on: any machine with kubectl access.
kubectl apply -f disallow-hostpid-psp-apps.yaml
Repeat for each user-workload namespace, changing metadata.name (namespace) and file name accordingly.
If your cluster uses the Pod Security Admission (PSA) labels instead of PodSecurityPolicy, you cannot express hostPID explicitly; you must instead rely on higher-level Pod Security standards and/or an external admission controller (see Manual Steps section for review and design – no kubectl-only deterministic fix exists in that model).
Verification (no pods using hostPID)
Run on: any machine with kubectl access.
kubectl get pods --all-namespaces -o json | \
jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end'
Automation
#!/usr/bin/env bash
#
# Block pods that request hostPID=true in all user namespaces
# by applying a restricted PodSecurity admission label.
#
# Requirements:
# - Run on any machine with kubectl access and cluster-admin rights.
# - jq must be installed.
#
# Idempotent: safe to re-run; uses kubectl apply / label --overwrite.
set -euo pipefail
# 1) Identify namespaces that currently allow hostPID pods (informational)
echo "Scanning for pods with hostPID=true..."
HOSTPID_PODS=$(kubectl get pods --all-namespaces -o json | \
jq -r '.items[] | select(.spec.hostPID == true) | "\(.metadata.namespace)/\(.metadata.name)"' || true)
if [ -n "${HOSTPID_PODS}" ]; then
echo "Found pods with hostPID=true:"
echo "${HOSTPID_PODS}"
else
echo "No existing pods with hostPID=true found."
fi
echo
echo "Applying restrictive PodSecurity labels to user namespaces..."
# 2) Select target namespaces
# Adjust the filter as needed to exclude system namespaces.
SYSTEM_NS_REGEX='^(kube-system|kube-public|kube-node-lease|default)$'
# Get all namespaces and filter out system ones
USER_NAMESPACES=$(kubectl get ns -o json | \
jq -r '.items[]
| select(.metadata.name | test("'"${SYSTEM_NS_REGEX}"'") | not)
| .metadata.name')
if [ -z "${USER_NAMESPACES}" ]; then
echo "No user namespaces found to label. Exiting."
exit 0
fi
# 3) Apply PodSecurity labels that disallow hostPID by enforcing restricted policy
# This uses Kubernetes Pod Security Admission (built-in to recent clusters).
for ns in ${USER_NAMESPACES}; do
echo "Labeling namespace: ${ns}"
# enforce restricted in baseline version; adjust version as needed for your cluster
kubectl label ns "${ns}" \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
--overwrite >/dev/null
done
echo
echo "Namespace labels after update:"
kubectl get ns --show-labels
# 4) Verification: ensure no pods with hostPID=true are admitted moving forward
# (this checks current state; admission prevention affects future creates/updates).
echo
echo "Verifying: checking again for pods with hostPID=true..."
VERIFY_OUTPUT=$(kubectl get pods --all-namespaces -o json | \
jq -r 'if any(.items[]?; .spec.hostPID == true) then "HOSTPID_FOUND" else "NO_HOSTPID" end')
echo "Verification result: ${VERIFY_OUTPUT}"
echo "Note: If HOSTPID_FOUND is reported, those pods were created before the policy change."
echo "New pods requesting hostPID=true in labeled namespaces should now be rejected."