Minimize Admission Of HostPath Volumes
More Info:
Do not generally admit containers which make use of hostPath volumes.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
List all workloads using
hostPathvolumes
Run on: any machine with kubectl accesskubectl get pods -A -o jsonpath='{range .items[?(@.spec.volumes)]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \| while read ns pod; dokubectl get pod "$pod" -n "$ns" -o json | \jq -r --arg ns "$ns" --arg pod "$pod" '.spec.volumes[]| select(has("hostPath"))| [$ns, $pod, .name, .hostPath.path, (.hostPath.type // "")]| @tsv'done | column -tUse this to identify which namespaces and pods currently depend on
hostPathand why (logging, runtime, node access, etc.). -
Review each namespace’s existing admission controls
Run on: any machine with kubectl accesskubectl get nskubectl get psp -A 2>/dev/null || truekubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration -Akubectl get clusterrole,clusterrolebinding -A | grep -i 'pod-security' || trueDetermine which namespaces host user workloads and whether they already enforce Pod Security Standards or other policies that restrict
hostPath. -
Decide namespace policy for
hostPathusage
For each namespace with user workloads:- Decide if
hostPathshould be:
a) Fully disallowed,
b) Allowed only for specific paths (e.g.,/var/log,/var/run), or
c) Temporarily allowed while refactoring workloads.
Document required exceptions (namespaces, deployments, and exact host paths).
- Decide if
-
Implement or tighten policy to restrict
hostPath
Run on: any machine with kubectl access
Examples (adapt to your chosen mechanism; apply only where appropriate):- If using Pod Security admission labels:
kubectl label namespace <NAMESPACE> pod-security.kubernetes.io/enforce=restricted --overwritekubectl label namespace <NAMESPACE> pod-security.kubernetes.io/audit=restricted --overwrite
- If using Kyverno (example policy – edit namespace selector, allowed paths):
cat << 'EOF' | kubectl apply -f -apiVersion: kyverno.io/v1kind: ClusterPolicymetadata:name: restrict-hostpathspec:validationFailureAction: enforcerules:- name: disallow-hostpathmatch:any:- resources:kinds:- Podnamespaces:- "<NAMESPACE>"validate:message: "hostPath volumes are not allowed in this namespace."pattern:spec:volumes:- X(hostPath): "null"EOF
- If using Pod Security admission labels:
-
Refactor or explicitly approve remaining
hostPathusers
For each pod identified in step 1 in namespaces wherehostPathshould be minimized:- Prefer alternatives (emptyDir, PVC, projected volumes, CSI drivers) and update manifests:
kubectl -n <NAMESPACE> get deploy <DEPLOYMENT> -o yaml > /tmp/deploy.yaml# Edit /tmp/deploy.yaml to remove/replace hostPath volumeskubectl -n <NAMESPACE> apply -f /tmp/deploy.yaml
- Where
hostPathis strictly necessary, ensure it is:- Limited to the minimal directory.
- Read-only where possible.
- Covered by an explicit, narrowly scoped policy exception.
- Prefer alternatives (emptyDir, PVC, projected volumes, CSI drivers) and update manifests:
-
Verify policies and current workloads
Run on: any machine with kubectl access- Confirm namespace labels / policy objects:
kubectl get ns --show-labelskubectl get clusterpolicy,policy -A 2>/dev/null || true
- Re-run
hostPathusage discovery to ensure only approved cases remain:# repeat step 1 - Optionally, perform a dry run of a pod using
hostPathin a locked-down namespace to confirm it is rejected:cat << 'EOF' | kubectl apply -f - --dry-run=serverapiVersion: v1kind: Podmetadata:name: test-hostpathnamespace: <NAMESPACE>spec:containers:- name: cimage: busyboxcommand: ["sleep","3600"]volumeMounts:- name: hpmountPath: /hostvolumes:- name: hphostPath:path: /tmpEOF
- Confirm namespace labels / policy objects:
Using kubectl
Using kubectl
1. List all namespaces to scope your review
Run on: any machine with kubectl access
kubectl get namespaces
You will review each namespace that runs user workloads (typically excluding kube-system, kube-public, kube-node-lease, and provider-specific system namespaces unless you intentionally run user apps there).
2. Check for pods using hostPath in each namespace
Run on: any machine with kubectl access
kubectl get pods -A -o jsonpath='{range .items[?(@.spec.volumes)]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[?(@.hostPath)]}{" volume: "}{.name}{" hostPath: "}{.hostPath.path}{"\n"}{end}{"---\n"}{end}'
Indications of a problem:
- Any pod in a user-workload namespace shows
volume: ... hostPath: /some/path. - Especially concerning paths:
/var/run,/var/run/docker.sock,/,/var/lib/kubelet,/etc,/var/lib/docker, or other sensitive host directories.
To drill into a specific namespace:
NAMESPACE=your-namespace
kubectl get pods -n "$NAMESPACE" -o yaml | grep -A5 "hostPath:"
3. Identify which controllers define those pods
Use labels or ownerReferences to find the workload owning a pod that uses hostPath.
Example (replace names as needed):
kubectl get pod -n your-namespace pod-name -o yaml
Look under .metadata.ownerReferences for kind (Deployment, DaemonSet, StatefulSet, Job, etc.), then inspect that controller:
kubectl get deployment -n your-namespace deployment-name -o yaml | grep -A8 "hostPath:"
kubectl get daemonset -n your-namespace ds-name -o yaml | grep -A8 "hostPath:"
kubectl get statefulset -n your-namespace sts-name -o yaml | grep -A8 "hostPath:"
Indications of a problem:
- Any user-managed controller spec includes
hostPath:under.spec.template.spec.volumes.
4. Check for PodSecurity or admission controls that restrict hostPath
4.1 Pod Security Admission (PSA) labels on namespaces
kubectl get ns --show-labels
Look for labels like:
pod-security.kubernetes.io/enforcepod-security.kubernetes.io/auditpod-security.kubernetes.io/warn
Indications of a problem:
- User-workload namespaces have no Pod Security labels, or:
- They are set to profiles (
baselineorprivileged) that allow broadhostPathusage when your policy should be more restrictive (e.g., targetingrestrictedand specific allowed host paths).
4.2 PodSecurityPolicy (legacy, if still present)
kubectl get psp
kubectl get psp -o yaml
In PSP definitions, inspect:
kubectl get psp psp-name -o yaml | grep -A15 "hostPath"
Indications of a problem:
volumesallowshostPathand:.spec.allowedHostPathsis empty, orpathPrefix: /or other very broad prefixes withoutreadOnly: truewhere appropriate.
- PSPs with broad
hostPathallowances are bound to service accounts used in user-workload namespaces.
To see which service accounts use a PSP (RBAC binding example):
kubectl get clusterrolebindings.rbac.authorization.k8s.io -o yaml | grep -B3 -A6 "kind: PodSecurityPolicy"
kubectl get rolebindings.rbac.authorization.k8s.io -A -o yaml | grep -B3 -A6 "kind: PodSecurityPolicy"
5. Check for validating/mutating admission webhooks related to hostPath
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io -o yaml
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io -o yaml
Search for hostPath in webhook configs and related CRDs/policies:
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations -o yaml | grep -i "hostPath" -n
Indications of a problem:
- No admission webhooks or policies mention
hostPathwhile your security model expects centralized enforcement (e.g., Kyverno, OPA Gatekeeper) to restrict or forbidhostPath. - Policies exist but are in
audit/warnmode only, notenforcefor hostPath usage.
6. If using common policy engines, surface hostPath-related rules
Examples (run only if the CRDs exist):
Kyverno:
kubectl get clusterpolicy,policy -A -o yaml | grep -i -n "hostPath"
Gatekeeper (OPA):
kubectl get k8sconstraints,configs,constrainttemplates -A -o yaml | grep -i -n "hostPath"
Indications of a problem:
- No constraints/policies reference
hostPathat all. - Constraints exist but target only limited namespaces, leaving user-workload namespaces unprotected.
7. What you decide from the review (human judgement required)
Based on the above data, you must decide:
- Which
hostPathusages are strictly required for functionality and acceptable by policy. - Where you should:
- Remove
hostPathentirely, - Replace it with a safer volume type (e.g.,
emptyDir, PVC), - Or constrain it via namespace policies/Pod Security/admission controls to a small set of approved paths and workloads.
- Remove
kubectl surfaces the current state; it does not decide or apply the correct restriction policy automatically.
Automation
#!/usr/bin/env bash
# Report namespaces and workloads that use hostPath volumes, and namespaces
# that do NOT have a policy restricting hostPath (PodSecurity or PSP-like).
set -euo pipefail
echo "=== 1) Namespaces with workloads using hostPath volumes ==="
echo
# This lists all pods with a hostPath volume and shows the namespace, pod,
# and the volume's path(s).
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| ($pod.spec.volumes // [])
| map(select(.hostPath != null))[]
| "\($pod.metadata.namespace)\t\($pod.metadata.name)\t\(.name)\t\(.hostPath.path)"
' 2>/dev/null \
| sort \
| awk 'BEGIN{print "NAMESPACE\tPOD\tVOLUME_NAME\tHOSTPATH_PATH"}1'
echo
echo "=== 2) Namespaces with PodSecurity Admission labels (v1.25+ clusters) ==="
echo "# Look for namespaces that allow privileged / unrestricted hostPath usage."
echo "# Commonly concerning labels (per namespace):"
echo "# pod-security.kubernetes.io/enforce"
echo "# pod-security.kubernetes.io/audit"
echo "# pod-security.kubernetes.io/warn"
echo
kubectl get ns --show-labels
echo
echo "=== 3) Namespaces and their PodSecurity levels (simplified view) ==="
echo "# This extracts key PodSecurity labels; missing or 'privileged' levels are higher risk."
echo
kubectl get ns -o json \
| jq -r '
.items[]
| [
.metadata.name,
(.metadata.labels["pod-security.kubernetes.io/enforce"] // "<none>"),
(.metadata.labels["pod-security.kubernetes.io/audit"] // "<none>"),
(.metadata.labels["pod-security.kubernetes.io/warn"] // "<none>")
]
| @tsv
' \
| awk 'BEGIN{print "NAMESPACE\tENFORCE\tAUDIT\tWARN"}1' \
| column -t
echo
echo "=== 4) Legacy PodSecurityPolicy (if present) and hostPath rules ==="
echo "# If PSP is enabled (older clusters / distributions), inspect hostPath controls."
echo "# Fields of interest in each PSP:"
echo "# spec.allowedHostPaths"
echo "# spec.volumes (whether hostPath is allowed at all)"
echo
if kubectl api-resources 2>/dev/null | grep -q '^podsecuritypolicies'; then
kubectl get podsecuritypolicies.policy -o json \
| jq -r '
.items[]
| [
.metadata.name,
(if (.spec.volumes // []) | index("hostPath") then "hostPath-ALLOWED" else "hostPath-NOT-ALLOWED" end),
(if (.spec.allowedHostPaths // []) | length > 0
then (.spec.allowedHostPaths | map(.pathPrefix + " (readOnly=" + (if .readOnly then "true" else "false" end) + ")") | join(", "))
else "<no allowedHostPaths restrictions>"
end)
]
| @tsv
' \
| awk 'BEGIN{print "PSP\tHOSTPATH_STATUS\tALLOWED_HOSTPATHS"}1' \
| column -t
else
echo "No PodSecurityPolicy API detected in this cluster."
fi
echo
echo "=== Interpretation / What indicates a problem? ==="
echo
cat <<'EOF'
Problem indicators to review manually:
1) From section (1):
- Any pod listed there is using a hostPath volume.
- Focus on:
* User / application namespaces (not core system namespaces like kube-system).
* hostPath paths that expose the node filesystem widely, such as:
/, /root, /var, /etc, /usr, /boot, /dev, /var/run/docker.sock, /run/containerd, etc.
- These should be justified by a clear operational need and additional controls.
2) From sections (2) and (3) – PodSecurity Admission:
- Namespaces with missing PodSecurity labels or labels set to 'privileged'
effectively allow unrestricted hostPath usage (among other things).
- Namespaces where:
ENFORCE is "<none>" or "privileged"
are higher risk and should be reviewed. Consider moving them to 'baseline' or 'restricted'
and explicitly allowing hostPath only where required.
3) From section (4) – PodSecurityPolicy (if in use):
- PSPs that:
* Include "hostPath" in spec.volumes
* AND have spec.allowedHostPaths empty or overly broad (e.g. "/")
allow broad hostPath usage.
- PSPs bound to user/application namespaces with such broad hostPath configuration
should be reviewed and constrained, or replaced with stricter policies.
This script does NOT change anything; it only surfaces where hostPath is used
and whether namespace-level or PSP-level controls are in place. Use this output
to decide where to add or tighten policies that restrict hostPath admission.
EOF