Skip to main content

Minimize The Admission Of Windows HostProcess Containers

More Info:

Windows HostProcess containers run with host-level privileges on the node. Restrict their admission in workload namespaces.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Identify Windows HostProcess workloads in user namespaces

    • Run on: any machine with kubectl access
    • Command (lists pods that explicitly request HostProcess):
      kubectl get pods --all-namespaces -o json \
      | jq -r '
      .items[]
      | select(.spec.securityContext.windowsOptions.hostProcess == true
      or ([.spec.containers[], (.spec.initContainers // [])[]?
      | select(.securityContext.windowsOptions.hostProcess == true)] | length) > 0)
      | [.metadata.namespace, .metadata.name] | @tsv
      '
    • Repeat, but exclude known infrastructure namespaces (adjust as appropriate for your cluster):
      kubectl get pods --all-namespaces -o json \
      | jq -r '
      .items[]
      | select(.metadata.namespace as $ns
      | ($ns | IN("kube-system","kube-public","kube-node-lease","kube-*","azure-*","aws-*","gke-*") | not))
      | select(.spec.securityContext.windowsOptions.hostProcess == true
      or ([.spec.containers[], (.spec.initContainers // [])[]?
      | select(.securityContext.windowsOptions.hostProcess == true)] | length) > 0)
      | [.metadata.namespace, .metadata.name] | @tsv
      '
  2. Decide where HostProcess containers are allowed (policy design)

    • For each user namespace, decide one of:
      • No HostProcess allowed (typical for most workloads).
      • HostProcess allowed only for specific, justified workloads (e.g., node maintenance agents).
    • Document for each namespace whether HostProcess is: forbidden, tightly controlled, or not yet decided.
  3. Review and, if needed, create/adjust admission controls (Pod Security or other)

    • If using built-in Pod Security Admission labels, for each user namespace that should forbid HostProcess, label it with at least baseline or restricted (both disallow HostProcess):
      # Example: enforce restricted profile, which disallows Windows HostProcess
      kubectl label namespace <USER_NAMESPACE> \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/enforce-version=latest \
      --overwrite
    • If you use another admission controller (e.g., Gatekeeper, Kyverno), review existing policies to ensure they deny pods with .securityContext.windowsOptions.hostProcess: true in any namespace that should not allow them. Use:
      kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io -o yaml
      kubectl get constrainttemplates,constraints,clusterpolicies,policies -A -o yaml 2>/dev/null | less
    • Where HostProcess must be allowed, design exception rules (e.g., labels/annotations on specific namespaces or service accounts) and ensure policies only allow HostProcess under those constrained conditions.
  4. Implement or tighten deny policies for HostProcess in user namespaces

    • Example Kyverno ClusterPolicy to deny all HostProcess containers except in explicitly allowed namespaces (windows-hostprocess-allowed=true):
      apiVersion: kyverno.io/v1
      kind: ClusterPolicy
      metadata:
      name: deny-windows-hostprocess
      spec:
      validationFailureAction: enforce
      background: true
      rules:
      - name: deny-hostprocess
      match:
      any:
      - resources:
      kinds:
      - Pod
      exclude:
      any:
      - resources:
      namespaces:
      - kube-system
      - resources:
      namespaceSelector:
      matchLabels:
      windows-hostprocess-allowed: "true"
      validate:
      message: "Windows HostProcess containers are not allowed in this namespace."
      pattern:
      spec:
      securityContext:
      windowsOptions:
      hostProcess: "false"
      containers:
      - (name): "*"
      securityContext:
      windowsOptions:
      hostProcess: "false"
      =(initContainers):
      - (name): "*"
      securityContext:
      windowsOptions:
      hostProcess: "false"
    • Apply (adjust as needed for your own policy engine):
      kubectl apply -f deny-windows-hostprocess.yaml
  5. Handle existing HostProcess pods in disallowed namespaces

    • For each pod from step 1 that is in a namespace now marked to forbid HostProcess:
      • Confirm with the owner whether the HostProcess capability is truly required.
      • If not required: update the pod spec / owning controller (Deployment, DaemonSet, Job, etc.) to remove .securityContext.windowsOptions.hostProcess: true, then redeploy.
      • If required: either
        • move the workload to a dedicated namespace explicitly marked to allow HostProcess (e.g., label windows-hostprocess-allowed=true), and keep strict controls there, or
        • adjust your policy design to formally permit it with documented justification.
  6. Verify that HostProcess admission is now minimized

    • Re-run the detection command to confirm there are no HostProcess pods in namespaces where they should be forbidden:
      kubectl get pods --all-namespaces -o json \
      | jq -r '
      .items[]
      | select(.spec.securityContext.windowsOptions.hostProcess == true
      or ([.spec.containers[], (.spec.initContainers // [])[]?
      | select(.securityContext.windowsOptions.hostProcess == true)] | length) > 0)
      | [.metadata.namespace, .metadata.name] | @tsv
      '
    • Independently test admission by attempting to create a sample HostProcess pod in a user namespace that should reject it and confirm it fails with a policy error:
      cat <<'EOF' | kubectl apply -f -
      apiVersion: v1
      kind: Pod
      metadata:
      name: test-hostprocess-deny
      namespace: <USER_NAMESPACE_THAT_SHOULD_DENY>
      spec:
      os:
      name: windows
      securityContext:
      windowsOptions:
      hostProcess: true
      containers:
      - name: test
      image: mcr.microsoft.com/windows/nanoserver:ltsc2022
      command: ["cmd", "/c", "ping -t 127.0.0.1"]
      securityContext:
      windowsOptions:
      hostProcess: true
      EOF
      Confirm the admission controller rejects this pod creation.
Using kubectl
# 1) List all namespaces that may host user workloads
# Run on: any machine with kubectl access
kubectl get ns

# 2) For each user-workload namespace, list policies that might control HostProcess:
# (ValidatingWebhookConfiguration, MutatingWebhookConfiguration, and constraints)
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations,validatingpolicies,validatingadmissionpolicies,clusterrolebindings,rolebindings -A

# 3) Identify current HostProcess usage in all namespaces
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.windowsOptions.hostProcess}{"\n"}{end}' \
| grep -iw "true" || echo "No pods with windowsOptions.hostProcess=true found"

# 4) Also check container-level windowsOptions on existing pods
kubectl get pods -A -o json \
| jq -r '
.items[]
| . as $pod
| ($pod.spec.containers[]?, $pod.spec.initContainers[]?)
| select(.securityContext.windowsOptions.hostProcess == true)
| [$pod.metadata.namespace, $pod.metadata.name, .name, "true"]
| @tsv
'

# 5) Inspect a specific namespace for HostProcess-true pods (replace NAMESPACE)
kubectl get pods -n kube-system -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.securityContext.windowsOptions.hostProcess}{"\n"}{end}' \
| grep -iw "true" || echo "No HostProcess pods in kube-system"

# 6) Look for policies that explicitly mention windowsOptions/hostProcess
kubectl get validatingwebhookconfigurations -o yaml | grep -nE 'windowsOptions|hostProcess' || echo "No hostProcess-related validating webhooks found"
kubectl get mutatingwebhookconfigurations -o yaml | grep -nE 'windowsOptions|hostProcess' || echo "No hostProcess-related mutating webhooks found"

# 7) If using ValidatingAdmissionPolicy (v1), inspect for hostProcess conditions
kubectl get validatingadmissionpolicies -o yaml | grep -nE 'windowsOptions|hostProcess' || echo "No hostProcess-related ValidatingAdmissionPolicies found"

Interpretation (what indicates a problem):

  • Step 3 / 4 / 5 outputs:

    • Any line where the last column is true means there is at least one Windows HostProcess container currently running in that namespace. That is not automatically wrong, but such pods should be reviewed and justified; user-workload namespaces should generally not contain HostProcess containers unless there is a documented, approved need.
  • Step 2 / 6 / 7 outputs:

    • If there are no Validating/Mutating webhooks or ValidatingAdmissionPolicies that reference windowsOptions or hostProcess, then there is likely no explicit admission control restricting Windows HostProcess containers.
    • In user-workload namespaces, “no hostProcess-related policies found” combined with evidence of HostProcess-true pods from steps 3–5 suggests a policy gap that needs human review and a possible policy design.

Verification after any policy changes:

# Re-check for admitted HostProcess containers
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.windowsOptions.hostProcess}{"\n"}{end}' \
| grep -iw "true" || echo "No pods with windowsOptions.hostProcess=true found"

# Confirm that at least one admission policy references hostProcess
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations,validatingadmissionpolicies -A -o yaml \
| grep -nE 'windowsOptions|hostProcess' || echo "No hostProcess-related admission controls detected"

These commands only surface state; a human must decide which namespaces may legitimately allow Windows HostProcess containers and what policy to apply.

Automation
#!/usr/bin/env bash
# Purpose:
# Report Windows HostProcess containers across all namespaces for review.
# Runs with: any machine with kubectl access and cluster-wide read permissions.

set -euo pipefail

echo "Scanning for Windows HostProcess containers in all namespaces..."
echo

# 1) List all pods that declare any HostProcess container
kubectl get pods -A -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
node: (.spec.nodeName // "UNSCHEDULED"),
os: (.spec.nodeSelector."kubernetes.io/os"
// .spec.nodeSelector."kubernetes.io/arch"
// "unknown"),
containers: (
[
(.spec.containers[]? | {name, hp: (.securityContext.windowsOptions.hostProcess // false), type:"container"}),
(.spec.initContainers[]? | {name, hp: (.securityContext.windowsOptions.hostProcess // false), type:"initContainer"}),
(.spec.ephemeralContainers[]? | {name, hp: (.securityContext.windowsOptions.hostProcess // false), type:"ephemeralContainer"})
]
)
}
| select([.containers[].hp] | any)
| [
.ns,
.pod,
.node,
.os,
(
.containers
| map(select(.hp == true) | "\(.type):\(.name)")
| join(",")
)
]
| @tsv
' 2>/dev/null \
| sort -k1,1 -k2,2 \
| awk 'BEGIN {
FS="\t";
printf "%-30s %-40s %-35s %-12s %s\n", "NAMESPACE", "POD", "NODE", "OS", "HOSTPROCESS_CONTAINERS";
print "---------------------------------------------------------------------------------------------------------------------------------------";
}
{
printf "%-30s %-40s %-35s %-12s %s\n", $1, $2, $3, $4, $5;
}'

echo
echo "Detail per HostProcess pod (namespace/pod -> container -> spec fragment):"
echo "---------------------------------------------------------------------------"

# 2) Show focused spec fragments for each HostProcess container for deeper review
kubectl get pods -A -o json \
| jq -r '
.items[]
| select(
[
(.spec.containers[]?.securityContext.windowsOptions.hostProcess // false),
(.spec.initContainers[]?.securityContext.windowsOptions.hostProcess // false),
(.spec.ephemeralContainers[]?.securityContext.windowsOptions.hostProcess // false)
] | any
)
| "---- " + .metadata.namespace + "/" + .metadata.name,
(
[
(.spec.containers[]? | select(.securityContext.windowsOptions.hostProcess == true)),
(.spec.initContainers[]? | select(.securityContext.windowsOptions.hostProcess == true)),
(.spec.ephemeralContainers[]? | select(.securityContext.windowsOptions.hostProcess == true))
]
| .[]
| "container: " + .name,
"spec:",
( { securityContext: { windowsOptions: .securityContext.windowsOptions } } | tojson ),
""
)
'

cat <<'EOF'

Interpretation / what indicates a problem
-----------------------------------------
- Any row in the summary table above indicates a pod that includes at least one
container with securityContext.windowsOptions.hostProcess = true.
- These pods should exist only where there is an explicit, justified operational
requirement (for example, privileged Windows node management DaemonSets).
- Findings that typically require action:
* HostProcess containers running in general-purpose application namespaces.
* HostProcess containers that were not explicitly approved by the security team.
* Namespaces where you expected policies (e.g., Pod Security Admission,
Gatekeeper, Kyverno) to deny HostProcess but the table still shows pods.

Use this report to:
- Identify namespaces that need admission controls to restrict HostProcess usage.
- Review each listed pod and decide whether to:
* Keep it (documented exception) and enforce tight controls; or
* Replace it with a non-HostProcess design and add/strengthen policies that
block future HostProcess containers in that namespace.

There is no safe, deterministic script to auto-fix these workloads: changes
must be made per-namespace and per-application, based on operational needs.
EOF