Skip to main content

Minimize The Admission Containers With Net_Raw Capability

More Info:

Do not generally permit containers to be run as the root user.

Risk Level

Critical

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS AKS
  • CIS Critical Security Controls v8
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Manual Steps
  1. From any machine with kubectl access, list all namespaces and identify which ones are allowed to run user workloads (exclude system namespaces such as kube-system, kube-public, kube-node-lease, gatekeeper-system, etc.):

    kubectl get ns
  2. For each non-system namespace, review what Pod Security controls are in place (PSPs if still in use, or Pod Security Admission labels / Gatekeeper / Kyverno, etc.). Start by checking Pod Security Admission labels:

    kubectl get ns --show-labels

    Look for pod-security.kubernetes.io/* labels. Namespaces lacking these labels or using privileged levels are higher risk and should be prioritized.

  3. In each high‑risk namespace, identify pods (and pod‑templates) that are currently using or could use extra capabilities by inspecting their securityContext:

    kubectl get pods -n <NAMESPACE> -o json | jq '.items[].spec.containers[]?.securityContext // {}'

    Also inspect common controllers:

    kubectl get deploy,sts,ds,job,cronjob -n <NAMESPACE> -o yaml | grep -nE 'securityContext|capabilities' -C2

    Manually review results for capabilities:, add:, especially any mention of NET_RAW.

  4. If PodSecurityPolicy (PSP) is still enabled in the cluster, list and inspect PSPs to see whether they require dropping NET_RAW:

    kubectl get psp
    kubectl get psp -o yaml | grep -nE 'requiredDropCapabilities|NET_RAW|ALL' -C3

    Determine whether all namespaces where workloads run are bound (via RBAC) to PSPs that have .spec.requiredDropCapabilities including NET_RAW or ALL. If not, note which namespaces and service accounts are effectively exempt.

  5. Based on the review, decide on changes:

    • For PSP-based clusters: design or update PSPs to include NET_RAW (or ALL) in .spec.requiredDropCapabilities and ensure appropriate RBAC bindings so all workload service accounts in your target namespaces are constrained by these PSPs.
    • For clusters without PSP: update or create equivalent admission controls (e.g., Gatekeeper/Kyverno policies, or rely on Pod Security Admission “restricted” profile) that enforce dropping NET_RAW, and update deployment manifests so containers do not explicitly add NET_RAW.
  6. After policy and manifest changes, re-check selected namespaces to confirm no pods can (or do) add NET_RAW:

    kubectl get deploy,sts,ds,job,cronjob -n <NAMESPACE> -o yaml | grep -nE 'capabilities' -C3

    If PSP is used, ensure all enforced PSPs now show requiredDropCapabilities including NET_RAW or ALL:

    kubectl get psp -o yaml | grep -nE 'requiredDropCapabilities' -C3
Using kubectl
# 1) List all namespaces and any PodSecurity standard labels
# Run on: any machine with kubectl access
kubectl get ns --show-labels

Problem indication:

  • Namespaces without any pod-security.kubernetes.io/* labels, or
  • Namespaces labeled pod-security.kubernetes.io/enforce=privileged (or unset but with privileged behavior configured elsewhere) suggest weaker controls, so NET_RAW is more likely to be allowed.
# 2) Inspect PodSecurity admission settings (if labels suggest problems)
# Replace <namespace> with a namespace of interest
kubectl describe ns <namespace>

Problem indication:

  • Labels: section missing pod-security.kubernetes.io/enforce or set to privileged.
  • No other admission mechanism (e.g., Gatekeeper, Kyverno) visible in annotations that would restrict capabilities.
# 3) Identify pods that explicitly add NET_RAW capability
# Run cluster-wide search
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].securityContext.capabilities.add}{"\n"}{end}' \
| grep -i NET_RAW || echo "No pods explicitly adding NET_RAW found"

Problem indication:

  • Any line where the third column includes NET_RAW shows a pod that is explicitly requesting this capability.
  • Focus especially on non-system namespaces where such capability is generally unnecessary.
# 4) Check for privileged or overly-permissive pods
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].securityContext.privileged}{"\n"}{end}' \
| grep -E "true$" || echo "No privileged pods reported"

Problem indication:

  • Any true value indicates a privileged container; privileged containers effectively bypass capability restrictions, so NET_RAW may be available even if not explicitly added.
# 5) Review workload manifests for capability configuration in a target namespace
# Replace <namespace> appropriately
kubectl get pod -n <namespace> -o yaml > /tmp/pods-<namespace>.yaml

Manually review the dumped YAML:

  • Look under spec.containers[].securityContext.capabilities.add for NET_RAW.
  • Check that spec.containers[].securityContext.capabilities.drop includes ALL or at least NET_RAW.

Problem indication:

  • Containers with capabilities.add including NET_RAW.
  • Containers missing a drop list, or with drop not including ALL or NET_RAW, in namespaces where this capability should not be allowed.
# 6) Verify whether legacy PodSecurityPolicies (if still enabled) restrict NET_RAW
kubectl get psp

If PSPs exist:

kubectl get psp -o yaml > /tmp/psp-all.yaml

Manually review:

  • Ensure .spec.requiredDropCapabilities includes NET_RAW or ALL.
  • Check any PSPs bound via Roles/ClusterRoles to the at‑risk namespaces.

Problem indication:

  • PSPs used by application namespaces where .spec.requiredDropCapabilities is empty, or
  • PSPs that do not include NET_RAW or ALL in requiredDropCapabilities, and are the ones applied to those namespaces.
Automation
#!/usr/bin/env bash
# Purpose: Report containers that can potentially use NET_RAW across the cluster
# Run on: any machine with kubectl access and current context set

set -euo pipefail

echo "=== 1) Cluster-wide PodSecurityPolicy (PSP) / PodSecurity admission overview ==="
# PSP is deprecated but still used in some clusters; also show PodSecurity labels.
echo
echo "--- PodSecurityPolicies (if any) ---"
kubectl get psp -o wide 2>/dev/null || echo "No PodSecurityPolicies found or PSP not supported"

echo
echo "--- Namespaces with Pod Security admission labels ---"
kubectl get ns -o json \
| jq -r '.items[] | {name: .metadata.name, labels: .metadata.labels} |
[.name,
( .labels["pod-security.kubernetes.io/enforce"] // "-" ),
( .labels["pod-security.kubernetes.io/enforce-version"] // "-" ),
( .labels["pod-security.kubernetes.io/audit"] // "-" ),
( .labels["pod-security.kubernetes.io/warn"] // "-" )
] | @tsv' 2>/dev/null \
| awk 'BEGIN{printf "%-30s %-10s %-10s %-10s %-10s\n","NAMESPACE","ENFORCE","ENF_VER","AUDIT","WARN"}
{printf "%-30s %-10s %-10s %-10s %-10s\n",$1,$2,$3,$4,$5}' \
|| echo "No Pod Security admission labels detected (or jq not installed)."

echo
echo "=== 2) Current pods with NET_RAW explicitly added via securityContext.capabilities ==="
echo "NOTE: This looks for NET_RAW in container securityContext; it does NOT detect"
echo " default capabilities inherited from the container runtime."

kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| ($pod.spec.containers + ($pod.spec.initContainers // []))[]
| . as $c
| {
ns: $pod.metadata.namespace,
pod: $pod.metadata.name,
container: .name,
adds: (.securityContext.capabilities.add // []),
drops: (.securityContext.capabilities.drop // [])
}
| select(.adds | index("NET_RAW"))
| "\(.ns)\t\(.pod)\t\(.container)\tadds:\(.adds|join(","))\tdrops:\(.drops|join(","))"
' 2>/dev/null \
| awk 'BEGIN{printf "%-30s %-40s %-25s %-30s %-30s\n","NAMESPACE","POD","CONTAINER","ADDS","DROPS"}
{printf "%-30s %-40s %-25s %-30s %-30s\n",$1,$2,$3,$4,$5}' \
|| echo "No pods with NET_RAW explicitly added found (or jq not installed)."

echo
echo "=== 3) Workload specs that add NET_RAW in Pod templates (Deployments, DaemonSets, etc.) ==="
echo "This finds controllers whose pod templates add NET_RAW; new pods from them will do the same."

# Helper function for controllers with pod templates
report_controller() {
local kind="$1"
echo
echo "--- ${kind}s with NET_RAW added ---"
kubectl get "${kind,,}" --all-namespaces -o json 2>/dev/null \
| jq -r --arg KIND "$kind" '
.items[]
| . as $obj
| ($obj.spec.template.spec.containers + ($obj.spec.template.spec.initContainers // []))[]
| . as $c
| {
kind: $KIND,
ns: $obj.metadata.namespace,
name: $obj.metadata.name,
container: .name,
adds: (.securityContext.capabilities.add // []),
drops: (.securityContext.capabilities.drop // [])
}
| select(.adds | index("NET_RAW"))
| "\(.kind)\t\(.ns)\t\(.name)\t\(.container)\tadds:\(.adds|join(","))\tdrops:\(.drops|join(","))"
' 2>/dev/null \
| awk -v K="$kind" 'BEGIN{printf "%-12s %-30s %-40s %-25s %-30s %-30s\n","KIND","NAMESPACE","NAME","CONTAINER","ADDS","DROPS"}
{printf "%-12s %-30s %-40s %-25s %-30s %-30s\n",$1,$2,$3,$4,$5,$6}' \
|| echo "No ${kind}s explicitly adding NET_RAW (or jq not installed)."
}

report_controller "Deployment"
report_controller "DaemonSet"
report_controller "StatefulSet"
report_controller "ReplicaSet"
report_controller "Job"
report_controller "CronJob"

echo
echo "=== 4) Namespaces where NET_RAW is NOT required to be dropped by PSP (if PSP present) ==="
echo "This section is only relevant if PodSecurityPolicy is enabled."

# List PSPs and whether they require dropping NET_RAW or ALL
kubectl get psp -o json 2>/dev/null \
| jq -r '
.items[]
| {
name: .metadata.name,
requiredDrops: (.spec.requiredDropCapabilities // [])
}
| "\(.name)\trequiredDrop:\(.requiredDrops|join(","))"
' 2>/dev/null \
| awk 'BEGIN{printf "%-40s %-40s\n","PSP","REQUIRED_DROP_CAPABILITIES"}
{printf "%-40s %-40s\n",$1,$2}' \
|| echo "No PSP data available; PSP may not be enabled or jq missing."

echo
echo "=== INTERPRETING RESULTS ==="
cat <<'EOF'
Potential problems that require review:

1) Pods / controllers explicitly adding NET_RAW:
- Any row in sections (2) or (3) indicates a container that *requests* NET_RAW.
- Review whether NET_RAW is strictly required for that workload.
- If not required, remove NET_RAW from securityContext.capabilities.add.
- Prefer dropping NET_RAW (or ALL) at policy level (PSP or Pod Security / admission) where possible.

2) Weak or missing cluster-wide policy:
- If no PSPs are present AND Pod Security admission labels are absent or set to a level
that allows NET_RAW (e.g., custom or "privileged"), then nothing is centrally preventing
workloads from using NET_RAW.
- Namespaces without Pod Security labels, or with very permissive settings, should be
reviewed and strengthened as appropriate for your environment.

This script does NOT:
- Detect implicit default capabilities granted by the container runtime.
- Enforce any policy automatically.

Use these reports to decide where to:
- Tighten policies (e.g., require dropping NET_RAW or ALL).
- Refactor workloads that currently rely on NET_RAW.
EOF

Additional Reading: