Skip to main content

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

Manual Steps
  1. List all workloads using hostPath volumes
    Run on: any machine with kubectl access

    kubectl get pods -A -o jsonpath='{range .items[?(@.spec.volumes)]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \
    | while read ns pod; do
    kubectl 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 -t

    Use this to identify which namespaces and pods currently depend on hostPath and why (logging, runtime, node access, etc.).

  2. Review each namespace’s existing admission controls
    Run on: any machine with kubectl access

    kubectl get ns
    kubectl get psp -A 2>/dev/null || true
    kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration -A
    kubectl get clusterrole,clusterrolebinding -A | grep -i 'pod-security' || true

    Determine which namespaces host user workloads and whether they already enforce Pod Security Standards or other policies that restrict hostPath.

  3. Decide namespace policy for hostPath usage
    For each namespace with user workloads:

    • Decide if hostPath should 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).
  4. 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 --overwrite
      kubectl 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/v1
      kind: ClusterPolicy
      metadata:
      name: restrict-hostpath
      spec:
      validationFailureAction: enforce
      rules:
      - name: disallow-hostpath
      match:
      any:
      - resources:
      kinds:
      - Pod
      namespaces:
      - "<NAMESPACE>"
      validate:
      message: "hostPath volumes are not allowed in this namespace."
      pattern:
      spec:
      volumes:
      - X(hostPath): "null"
      EOF
  5. Refactor or explicitly approve remaining hostPath users
    For each pod identified in step 1 in namespaces where hostPath should 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 volumes
      kubectl -n <NAMESPACE> apply -f /tmp/deploy.yaml
    • Where hostPath is strictly necessary, ensure it is:
      • Limited to the minimal directory.
      • Read-only where possible.
      • Covered by an explicit, narrowly scoped policy exception.
  6. Verify policies and current workloads
    Run on: any machine with kubectl access

    • Confirm namespace labels / policy objects:
      kubectl get ns --show-labels
      kubectl get clusterpolicy,policy -A 2>/dev/null || true
    • Re-run hostPath usage discovery to ensure only approved cases remain:
      # repeat step 1
    • Optionally, perform a dry run of a pod using hostPath in a locked-down namespace to confirm it is rejected:
      cat << 'EOF' | kubectl apply -f - --dry-run=server
      apiVersion: v1
      kind: Pod
      metadata:
      name: test-hostpath
      namespace: <NAMESPACE>
      spec:
      containers:
      - name: c
      image: busybox
      command: ["sleep","3600"]
      volumeMounts:
      - name: hp
      mountPath: /host
      volumes:
      - name: hp
      hostPath:
      path: /tmp
      EOF
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/enforce
  • pod-security.kubernetes.io/audit
  • pod-security.kubernetes.io/warn

Indications of a problem:

  • User-workload namespaces have no Pod Security labels, or:
  • They are set to profiles (baseline or privileged) that allow broad hostPath usage when your policy should be more restrictive (e.g., targeting restricted and 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:

  • volumes allows hostPath and:
    • .spec.allowedHostPaths is empty, or
    • pathPrefix: / or other very broad prefixes without readOnly: true where appropriate.
  • PSPs with broad hostPath allowances 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"

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 hostPath while your security model expects centralized enforcement (e.g., Kyverno, OPA Gatekeeper) to restrict or forbid hostPath.
  • Policies exist but are in audit/warn mode only, not enforce for hostPath usage.

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 hostPath at 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 hostPath usages are strictly required for functionality and acceptable by policy.
  • Where you should:
    • Remove hostPath entirely,
    • 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.

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

Additional Reading: