Minimize Admission Of Containers With NET_RAW Capability
More Info:
Do not generally permit containers with the potentially dangerous NET_RAW capability.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify namespaces with user workloads and existing Pod Security controls
- Run on: any machine with kubectl access
kubectl get nskubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels}{"\n"}{end}'kubectl get psp 2>/dev/null || echo "No PodSecurityPolicies found"kubectl get validatingwebhookconfigurations.admissionregistration.k8s.iokubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io- Decide which namespaces are for user workloads and require explicit restriction.
-
Review current use of NET_RAW in existing workloads
- Run on: any machine with kubectl access
# List pods that explicitly add NET_RAWkubectl get pods --all-namespaces -o json \| jq -r '.items[] |.metadata.namespace as $ns |.metadata.name as $pod |(.spec.containers[]?, .spec.initContainers[]?) as $c |($c.securityContext.capabilities.add[]? // empty) as $cap |select($cap == "NET_RAW") |[$ns, $pod, $c.name, $cap] | @tsv'# List pods that drop all capabilities (good baseline)kubectl get pods --all-namespaces -o json \| jq -r '.items[] |.metadata.namespace as $ns |.metadata.name as $pod |(.spec.containers[]?, .spec.initContainers[]?) as $c |select($c.securityContext.capabilities.drop[]? == "ALL") |[$ns, $pod, $c.name] | @tsv'- For each workload using NET_RAW, confirm whether it is strictly required for functionality.
-
Decide the policy mechanism to enforce NET_RAW restriction per namespace
- If using built-in Pod Security Admission (PSA):
Decide whether to move namespaces tokubectl get ns --show-labels
restrictedor keepbaselineand add an admission policy for NET_RAW. - If using OPA Gatekeeper or Kyverno, decide which policy engine to use or extend.
- If using built-in Pod Security Admission (PSA):
-
Review or define namespace-level policies that deny NET_RAW
- Example Gatekeeper audit (if Gatekeeper installed):
kubectl get k8sallowedcapabilities.constraints.gatekeeper.sh -Akubectl get k8spspallowedcapabilities.constraints.gatekeeper.sh -A
- Example Kyverno audit (if Kyverno installed):
kubectl get clusterpolicy,policy -A
- For each user-workload namespace, ensure there is a policy that either forbids
NET_RAWentirely or allows it only for explicitly named workloads. If missing, plan to create such a policy (e.g., Gatekeeper Constraint or Kyverno Policy) targeting that namespace.
- Example Gatekeeper audit (if Gatekeeper installed):
-
Tighten or add securityContext in manifests for required exceptions
- For workloads that legitimately need NET_RAW, explicitly declare and isolate the requirement in their manifests so policies can allow only those:
# Example: inspect a specific deployment manifestkubectl get deploy -n <namespace> <deployment-name> -o yaml- Ensure manifests for workloads that do not need NET_RAW either omit capability additions or explicitly drop all capabilities:
securityContext:allowPrivilegeEscalation: falsecapabilities:drop: ["ALL"] -
Verify that admission is now minimized for NET_RAW
- After updating policies and manifests, test admission in a user-workload namespace that should be restricted:
cat <<'EOF' | kubectl apply -n <user-namespace> -f -apiVersion: v1kind: Podmetadata:name: net-raw-test-denyspec:containers:- name: cimage: busyboxcommand: ["sleep", "3600"]securityContext:capabilities:add: ["NET_RAW"]EOF- Confirm that this pod is rejected with an admission error referring to the policy (or, if allowed by design in a specific exception namespace, confirm that it is the only such namespace and that others are denied).
Using kubectl
# 1. List all namespaces so you can decide which host user workloads
# Run on: any machine with kubectl access
kubectl get ns -o name
A problem exists if you find namespaces that run user workloads but have no policy objects controlling capabilities (next steps).
# 2. For each user-workload namespace, list PodSecurityPolicies (if used)
# Replace NAMESPACE with the target namespace
kubectl get podsecuritypolicies.policy -o yaml
Problem indicators:
- PSPs exist that are referenced by your workloads’ ServiceAccounts (RBAC bindings), and:
.spec.allowedCapabilitiesincludesNET_RAW, or.spec.defaultAddCapabilitiesincludesNET_RAW, or.spec.requiredDropCapabilitiesdoes not includeNET_RAWwhile other caps are restricted
- Or: there is no PSP at all in a cluster where PSP is the intended control.
# 3. For each user-workload namespace, list local security policies
# Run on: any machine with kubectl access
# Pod Security admission labels on the namespace
kubectl get ns NAMESPACE -o yaml
# PodSecurityPolicy (legacy) references via RBAC (optional deeper check)
kubectl get role,rolebinding,clusterrole,clusterrolebinding -n NAMESPACE -o yaml
Problem indicators:
- Namespace has no Pod Security admission labels (e.g.
pod-security.kubernetes.io/enforce), so you rely only on ad‑hoc controls. - RBAC bindings grant access to permissive PSPs (from previous step) that allow
NET_RAW.
# 4. Inspect PodSpecs in the namespace for explicit NET_RAW use
# Run on: any machine with kubectl access
# Current running Pods
kubectl get pods -n NAMESPACE -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{range .spec.containers[*]} {.name}{" capsAdd:"}{.securityContext.capabilities.add}{" capsDrop:"}{.securityContext.capabilities.drop}{"\n"}{end}{"\n"}{end}'
# All workload controllers (Deployments, DaemonSets, etc.)
kubectl get deploy,sts,ds,job,cronjob -n NAMESPACE -o yaml
Problem indicators:
- Any container shows
capsAdd:[NET_RAW ...]or similar in.securityContext.capabilities.add. - Workload manifests define
securityContext.capabilities.addincludingNET_RAW, or fail to drop it when your policy model expects explicit dropping.
# 5. Check for namespace-level defaulting via mutating/validating webhooks
# Run on: any machine with kubectl access
kubectl get mutatingwebhookconfigurations,validatingwebhookconfigurations -o yaml
Problem indicators:
- Webhooks that add
NET_RAWto container capabilities. - Absence of any validating webhook that enforces dropping
NET_RAWwhen your security model expects such enforcement.
# 6. If using Pod Security Admission (PSA), verify the effective level
# Run on: any machine with kubectl access
kubectl label ns NAMESPACE --list
Problem indicators:
- Namespace labels such as:
pod-security.kubernetes.io/enforce=privileged- or no
pod-security.kubernetes.io/*labels at all
- In these cases, containers may run with
NET_RAWunless controlled by other mechanisms.
# 7. Spot-check a known sensitive namespace for an example Pod
# Run on: any machine with kubectl access
kubectl get pod PODNAME -n NAMESPACE -o yaml
Problem indicators:
- Under
spec.containers[].securityContext.capabilities.add,NET_RAWis present without a strong, documented business justification. - There is no organizational pattern (annotations, labels, documentation) explaining why
NET_RAWis required.
Automation
#!/usr/bin/env bash
set -euo pipefail
# This script inspects all namespaces for policies that restrict the NET_RAW capability.
# It does NOT change anything; it only reports for review.
echo "=== Cluster-wide NET_RAW admission review ==="
echo
echo "1) Namespaces and PodSecurity admission levels (if enabled)"
echo "----------------------------------------------------------"
kubectl get ns -o json | jq -r '
.items[]
| .metadata as $m
| (
$m.labels."pod-security.kubernetes.io/enforce",
$m.labels."pod-security.kubernetes.io/warn",
$m.labels."pod-security.kubernetes.io/audit"
) as $ps
| [
$m.name,
$m.labels."pod-security.kubernetes.io/enforce",
$m.labels."pod-security.kubernetes.io/enforce-version",
$m.labels."pod-security.kubernetes.io/warn",
$m.labels."pod-security.kubernetes.io/warn-version",
$m.labels."pod-security.kubernetes.io/audit",
$m.labels."pod-security.kubernetes.io/audit-version"
]
| @tsv' \
| awk 'BEGIN {
OFS="\t";
print "NAMESPACE","ENFORCE","ENFORCE_VER","WARN","WARN_VER","AUDIT","AUDIT_VER"
} {print}'
echo
echo "Problem indication for step 1:"
echo "- Namespaces running user workloads that are NOT labeled with at least ENFORCE=baseline or ENFORCE=restricted"
echo " may allow NET_RAW unless another policy (PSP/Gatekeeper/PodSecurityPolicy replacement) blocks it."
echo
echo "2) PodSecurityPolicies (if still present) and their NET_RAW rules"
echo "-----------------------------------------------------------------"
if kubectl api-resources | grep -q "^podsecuritypolicies.extensions" || \
kubectl api-resources | grep -q "^podsecuritypolicies.policy"; then
kubectl get podsecuritypolicies -o json | jq -r '
.items[]
| .metadata.name as $name
| .spec as $s
| $s.requiredDropCapabilities as $reqDrop
| $s.allowedCapabilities as $allowed
| $s.defaultAddCapabilities as $defaultAdd
| [
$name,
(if ($reqDrop // []) | index("NET_RAW") then "YES" else "NO" end),
(if ($allowed // []) | index("NET_RAW") then "YES" else "NO" end),
(if ($defaultAdd // []) | index("NET_RAW") then "YES" else "NO" end)
]
| @tsv' \
| awk 'BEGIN {
OFS="\t";
print "PSP","REQUIRES_DROP_NET_RAW","ALLOWS_NET_RAW","DEFAULT_ADDS_NET_RAW"
} {print}'
else
echo "No PodSecurityPolicy API detected in this cluster."
fi
echo
echo "Problem indication for step 2:"
echo "- Any PSP that:"
echo " * does NOT require dropping NET_RAW (REQUIRES_DROP_NET_RAW=NO) AND"
echo " * either ALLOWS_NET_RAW=YES or DEFAULT_ADDS_NET_RAW=YES"
echo " indicates a risk that containers can keep or gain NET_RAW."
echo
echo "3) Gatekeeper/OPA or Kyverno-like policies mentioning NET_RAW (if installed)"
echo "---------------------------------------------------------------------------"
echo "# Gatekeeper/OPA constraints and templates referencing NET_RAW:"
if kubectl api-resources | grep -qi 'constrainttemplate'; then
kubectl get constrainttemplates -A -o yaml | grep -n --color=always -i 'NET_RAW' || \
echo "No NET_RAW references found in ConstraintTemplates."
echo
kubectl get constraints -A -o yaml 2>/dev/null | grep -n --color=always -i 'NET_RAW' || \
echo "No NET_RAW references found in Constraints."
else
echo "No Gatekeeper ConstraintTemplate API detected."
fi
echo
echo "# Kyverno ClusterPolicies/Policies referencing NET_RAW:"
if kubectl api-resources | grep -qi '^clusterpolicies.kyverno.io'; then
kubectl get clusterpolicies -A -o yaml | grep -n --color=always -i 'NET_RAW' || \
echo "No NET_RAW references found in Kyverno ClusterPolicies."
fi
if kubectl api-resources | grep -qi '^policies.kyverno.io'; then
kubectl get policies -A -o yaml | grep -n --color=always -i 'NET_RAW' || \
echo "No NET_RAW references found in Kyverno Policies."
fi
echo
echo "Problem indication for step 3:"
echo "- Absence of any admission policies (Gatekeeper/Kyverno or similar) that:"
echo " * explicitly require dropping NET_RAW, or"
echo " * forbid adding NET_RAW,"
echo " in namespaces without strict PodSecurity admission."
echo
echo "4) Workload specs that currently request or retain NET_RAW"
echo "---------------------------------------------------------"
echo "Scanning Pods, Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs for NET_RAW..."
echo
resources=(
"pods"
"deployments.apps"
"statefulsets.apps"
"daemonsets.apps"
"jobs.batch"
"cronjobs.batch"
)
for r in "${resources[@]}"; do
echo "== $r =="
if ! kubectl get "$r" --all-namespaces >/dev/null 2>&1; then
echo " (resource type not found or not used)"
echo
continue
fi
kubectl get "$r" --all-namespaces -o json | jq -r '
.items[]
| .metadata as $m
| .spec as $s
| (
if .kind=="Pod" then $s
else
# handle controllers with pod templates
( if $s.template then $s.template.spec else $s end )
end
) as $pspec
| ($pspec.containers // []) as $containers
| ($pspec.initContainers // []) as $initContainers
| ($pspec.ephemeralContainers // []) as $ephContainers
| [$containers[], $initContainers[], $ephContainers[]]?
| select(. != null)
| .name as $cname
| .securityContext as $csec
| $pspec.securityContext as $psec
| [
$m.namespace,
$m.name,
.image,
$cname,
(
if ($csec.capabilities.drop // []) | index("NET_RAW")
then "YES"
else "NO"
end
),
(
if ($csec.capabilities.add // []) | index("NET_RAW")
then "YES"
else "NO"
end
),
(
if ($psec.capabilities.drop // []) | index("NET_RAW")
then "YES"
else "NO"
end
),
(
if ($psec.capabilities.add // []) | index("NET_RAW")
then "YES"
else "NO"
end
)
]
| @tsv' 2>/dev/null \
| awk 'BEGIN {
OFS="\t";
print "NAMESPACE","WORKLOAD_NAME","IMAGE","CONTAINER",
"CONTAINER_DROPS_NET_RAW","CONTAINER_ADDS_NET_RAW",
"POD_DROPS_NET_RAW","POD_ADDS_NET_RAW"
} {print}'
echo
done
echo "Problem indication for step 4:"
echo "- Any line where:"
echo " * CONTAINER_ADDS_NET_RAW=YES or POD_ADDS_NET_RAW=YES -> container explicitly gains NET_RAW."
echo " * CONTAINER_DROPS_NET_RAW=NO and POD_DROPS_NET_RAW=NO -> no explicit drop;"
echo " combined with weak PodSecurity/admission policy this may allow NET_RAW to be retained."
echo
echo "Review guidance:"
echo "- Focus on user-workload namespaces that lack strict PodSecurity or other admission controls."
echo "- In those namespaces, identify workloads with ADDS_NET_RAW=YES or that do not drop NET_RAW."
echo "- Decide case-by-case whether NET_RAW is strictly required; if not, adjust manifests or add policies"
echo " (per-namespace admission controls) to require dropping NET_RAW or forbid adding it."