Minimize The Admission Of HostPath Volumes
More Info:
hostPath volumes mount node filesystem paths into containers, enabling access to sensitive host files and escape. Restrict their admission.
Risk Level
High
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify current use of
hostPathvolumes across the cluster- Run on: any machine with kubectl access
- Command:
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[?(@.hostPath)]}{" hostPath: "}{.hostPath.path}{"\n"}{end}{end}' | grep -B1 'hostPath' || echo "No hostPath volumes found"
- Review which namespaces and pods are using
hostPath, and whether they are system components (e.g., inkube-system) or user workloads.
-
Determine which namespaces require protection (user workloads)
- Run on: any machine with kubectl access
- Command to list namespaces:
kubectl get namespaces
- Classify namespaces into:
- System/control-plane (e.g.,
kube-system,kube-node-lease,kube-public) - Add-on/infra namespaces where
hostPathmay be intentionally required - User workload namespaces (targets for strong restriction)
- System/control-plane (e.g.,
-
Design the admission policy for
hostPathin user namespaces- Decide, per user namespace, whether:
hostPathshould be completely disallowed, or- Only specific, narrowly scoped paths are allowed (e.g., a CSI driver)
- If using an admission controller framework (e.g., ValidatingAdmissionPolicy, Kyverno, Gatekeeper), select the mechanism you will use to enforce
hostPathrestrictions in those namespaces.
- Decide, per user namespace, whether:
-
Implement or update policies to restrict
hostPathin user namespaces- Run on: any machine with kubectl access
- Example: create a strict
ValidatingAdmissionPolicythat denies allhostPathvolumes in selected namespaces (adjust namespaces as needed):cat << 'EOF' | kubectl apply -f -apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata:name: deny-hostpath-volumesspec:failurePolicy: FailmatchConstraints:resourceRules:- apiGroups: [""]apiVersions: ["v1"]operations: ["CREATE", "UPDATE"]resources: ["pods"]validations:- expression: "!(has(object.spec.volumes) && object.spec.volumes.exists(v, has(v.hostPath)))"message: "hostPath volumes are not allowed in this cluster/namespace."---apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata:name: deny-hostpath-volumes-bindingspec:policyName: deny-hostpath-volumesvalidationActions: [ "Deny" ]matchResources:namespaceSelector:matchExpressions:- key: kubernetes.io/metadata.nameoperator: Invalues:- user-namespace-1- user-namespace-2EOF - If you must allow specific
hostPathpaths, adjust theexpressionto allow only those paths instead of denying allhostPath.
-
Test enforcement and handle existing workloads
- Run on: any machine with kubectl access
- Try to deploy a test pod with a
hostPathvolume into a protected namespace and confirm it is rejected:cat << 'EOF' | kubectl apply -f -apiVersion: v1kind: Podmetadata:name: hostpath-test-denynamespace: user-namespace-1spec:containers:- name: testimage: busyboxcommand: ["sleep", "3600"]volumeMounts:- name: hpmountPath: /mntvolumes:- name: hphostPath:path: /tmpEOF - For existing pods using
hostPathin user namespaces, review whether they are justified; if not, plan to:- Update the workloads to remove
hostPath, then - Redeploy them so that policy is applied on the next create/update.
- Update the workloads to remove
-
Re-verify cluster state after changes
- Run on: any machine with kubectl access
- Confirm no unintended
hostPathuse remains in user namespaces:kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[?(@.hostPath)]}{" hostPath: "}{.hostPath.path}{"\n"}{end}{end}' | grep -B1 'hostPath' || echo "No hostPath volumes found" - Confirm the admission policy objects are present and active:
kubectl get validatingadmissionpolicieskubectl get validatingadmissionpolicybindings
Using kubectl
# 1) List all namespaces that may need policy
# Run on: any machine with kubectl access
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'
Look for all namespaces that host user workloads (typically everything except kube-*, kubernetes-dashboard, istio-system, etc., depending on your environment). Those are the ones that must have a restriction policy.
# 2) Check for Pods currently using hostPath volumes (cluster-wide)
# Run on: any machine with kubectl access
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[*]}{" volume: "}{.name}{" type: "}{.hostPath.path}{"\n"}{end}{"---\n"}{end}' 2>/dev/null | grep hostPath -B1
Problem indication:
- Any line showing
hostPath.path(e.g./var/run/docker.sock,/,/var/lib/kubelet,/etc, etc.) is a Pod that mounts the node filesystem. - Each such Pod must be manually reviewed for necessity and scope of the hostPath.
# 3) For a specific namespace, list only Pods with hostPath
# Replace <namespace>
kubectl get pod -n <namespace> -o json | \
jq -r '.items[] | select(.spec.volumes[]? | has("hostPath")) |
.metadata.name as $p |
.spec.volumes[]? |
select(has("hostPath")) |
"\($p) \t volume=\(.name) \t path=\(.hostPath.path)"'
Problem indication:
- Any user workload namespace with Pods listed here is using hostPath.
- Broad or sensitive paths (like
/,/var,/etc,/var/lib,/var/run) are higher risk.
# 4) Inspect one Pod’s full spec to understand why hostPath is used
# Replace <namespace> and <pod>
kubectl get pod -n <namespace> <pod> -o yaml
Problem indication:
.spec.volumes[*].hostPath.pathmounted withhostPath.type: ""orDirectorywithout constraints.- Combined with
securityContext.privileged: true,allowPrivilegeEscalation: true, orrunAsUser: 0indicates high breakout risk.
# 5) Check for existing admission policies that mention hostPath (PodSecurityPolicies, if present)
kubectl get podsecuritypolicies.policy -o yaml 2>/dev/null | \
grep -nE 'hostPath|volumes' -n || echo "No PodSecurityPolicies or no hostPath references found"
Problem indication:
- Absence of PSPs (on clusters that still support them) or PSPs that allow
hostPathvolumes without restriction in namespaces where you found hostPath Pods.
# 6) Check namespace-level Pod Security admission (if enabled in the cluster)
# Replace <namespace>
kubectl get ns <namespace> -o yaml | grep -i 'pod-security'
Problem indication:
- For user namespaces, labels like
pod-security.kubernetes.io/enforce: privileged(or no labels at all) combined with hostPath usage means there is no baseline/restricted control to constrain such volumes.
# 7) Check Validating/MutatingWebhookConfigurations for policies handling hostPath
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations -o yaml 2>/dev/null | \
grep -n 'hostPath' -n || echo "No admission webhooks explicitly referencing hostPath found"
Problem indication:
- No admission webhooks addressing
hostPathin a cluster where you depend on external policy (OPA Gatekeeper, Kyverno, etc.) to restrict such volumes.
Use these commands to:
- Enumerate where hostPath is used.
- Determine which namespaces run hostPath workloads.
- Verify whether any admission control mechanism currently restricts hostPath. Human review is required to decide which hostPath uses are justified and what policies to apply to each namespace.
Automation
#!/usr/bin/env bash
# Report use of hostPath volumes across all namespaces
# Run on: any machine with kubectl access and correct KUBECONFIG
set -euo pipefail
echo "Scanning all pods for hostPath volume usage..."
echo
# 1) High‑level summary: which pods use hostPath and how many
echo "=== Summary of pods using hostPath volumes ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
hostPaths: (
[.spec.volumes[]
| select(.hostPath != null)
| {name, path: .hostPath.path, type: (.hostPath.type // "")}
] // []
)
}
| select(.hostPaths | length > 0)
| .ns + "\t" + .pod + "\t" + ( (.hostPaths | length) | tostring )
' \
| awk 'BEGIN { print "NAMESPACE\tPOD\tHOSTPATH_VOLUME_COUNT" }1'
echo
# 2) Detailed report: each hostPath volume with path/type and pod SA
echo "=== Detailed hostPath usage (one line per hostPath volume) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| ($pod.spec.volumes // [])
| map(select(.hostPath != null))
| .[]
| [
$pod.metadata.namespace,
$pod.metadata.name,
($pod.spec.serviceAccountName // "default"),
.name,
.hostPath.path,
(.hostPath.type // "")
]
| @tsv
' \
| awk '
BEGIN {
OFS="\t";
print "NAMESPACE","POD","SERVICEACCOUNT","VOLUME_NAME","HOSTPATH_PATH","HOSTPATH_TYPE"
}
{ print }
'
echo
# 3) Optional: filter out known system namespaces (tune as needed)
echo "=== Non-system namespaces using hostPath (candidate review targets) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| select(.metadata.namespace
| IN("kube-system","kube-public","kube-node-lease") | not)
| . as $pod
| ($pod.spec.volumes // [])
| map(select(.hostPath != null))
| .[]
| [
$pod.metadata.namespace,
$pod.metadata.name,
($pod.spec.serviceAccountName // "default"),
.name,
.hostPath.path,
(.hostPath.type // "")
]
| @tsv
' \
| awk '
BEGIN {
OFS="\t";
print "NAMESPACE","POD","SERVICEACCOUNT","VOLUME_NAME","HOSTPATH_PATH","HOSTPATH_TYPE"
}
{ print }
'
echo "Scan complete."
How to interpret the output
- Any line in the summaries indicates a pod that is using a
hostPathvolume. - Focus review on:
- Non‑system namespaces (third section).
- Sensitive paths (examples:
/,/var/run,/var/lib/kubelet,/etc,/var/lib/docker,/var/run/docker.sock,/run/containerd,/var/lib/containerd,/host,/proc,/sys). - Pods running under broadly scoped or shared service accounts.
- Pods in user/workload namespaces using
hostPathare candidates for:- Refactoring to use PVCs or other volume types.
- Being constrained by admission policy (e.g., Pod Security / ValidatingAdmissionPolicy / external admission controllers) to prevent or tightly control
hostPathusage.