Skip to main content

Minimize The Admission Containers With The Net Raw

More Info:

Do not generally permit containers with the potentially dangerous NET_RAW capability.

Risk Level

Medium

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS EKS
  • 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. List current workload security settings (PSPs, PSP replacements, and policies)
    Run on: any machine with kubectl access

    # PodSecurityPolicy (if still in use)
    kubectl get podsecuritypolicies.policy

    # Pod Security Admission (PSA) labels on namespaces (for newer clusters)
    kubectl get ns --show-labels | grep -E 'pod-security\.kubernetes\.io/(enforce|audit|warn)='

    # Common admission controllers: Gatekeeper, Kyverno, custom webhooks
    kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io
    kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io
    kubectl get cpol,pol,clustercpol -A 2>/dev/null || true
  2. Discover pods that currently have NET_RAW capability
    Run on: any machine with kubectl access

    kubectl get pods -A -o json \
    | jq -r '
    .items[]
    | .metadata as $m
    | (.spec.initContainers[]?, .spec.containers[]?) as $c
    | select(
    ($c.securityContext.capabilities.add[]? // "") == "NET_RAW"
    or
    (($c.securityContext.capabilities.drop // []) | index("ALL") | not)
    )
    | "\($m.namespace) \($m.name) \($c.name)"' | sort -u

    Review the output and identify which workloads:

    • explicitly add NET_RAW, or
    • fail to drop NET_RAW by not dropping ALL (and not dropping NET_RAW specifically).
  3. Review pod and namespace security configuration for each affected workload
    For each (namespace, pod, container) from step 2:

    # Show full pod spec
    kubectl get pod -n <NAMESPACE> <POD_NAME> -o yaml

    # Show namespace labels / PSA configuration
    kubectl get ns <NAMESPACE> -o yaml

    # If PSP is used, see which PSP applies (cluster-specific process; as a proxy list PSPs)
    kubectl describe pod -n <NAMESPACE> <POD_NAME> | sed -n '1,80p'

    Manually check:

    • securityContext.capabilities.add for NET_RAW
    • securityContext.capabilities.drop includes ALL or at least NET_RAW
    • Whether any namespace or policy enforces a required drop of NET_RAW/ALL.
  4. Decide if each use of NET_RAW is strictly necessary
    For each affected container, consult the owning team and application documentation to determine:

    • Is raw socket / packet crafting actually required (e.g., low-level networking, certain monitoring agents, specialized load balancers)?
    • If yes, can the function be achieved using higher‑level networking APIs or sidecar patterns instead?
    • If no, plan to remove NET_RAW by:
      • eliminating it from securityContext.capabilities.add, and/or
      • adding NET_RAW or ALL to securityContext.capabilities.drop.
  5. Adjust policies/manifests to require dropping NET_RAW (or ALL) where safe
    Based on step 4 decisions:

    • For namespace/workload manifests (Deployment/DaemonSet/Job/etc.), edit source manifests or Helm charts to:
      • Remove any NET_RAW from securityContext.capabilities.add.
      • Add:
        securityContext:
        capabilities:
        drop:
        - ALL
        or at minimum:
        securityContext:
        capabilities:
        drop:
        - NET_RAW
    • For cluster-wide admission controls (PSP if still used, or equivalent OPA/Gatekeeper/Kyverno policies), configure rules that:
      • Require NET_RAW to be dropped, or
      • Forbid adding NET_RAW, except for carefully scoped exceptions (namespaces/labels).
  6. Verify that NET_RAW is no longer generally admitted
    After redeploying updated workloads and/or policies, re-run:

    kubectl get pods -A -o json \
    | jq -r '
    .items[]
    | .metadata as $m
    | (.spec.initContainers[]?, .spec.containers[]?) as $c
    | select(
    ($c.securityContext.capabilities.add[]? // "") == "NET_RAW"
    or
    (($c.securityContext.capabilities.drop // []) | index("ALL") | not)
    )
    | "\($m.namespace) \($m.name) \($c.name)"' | sort -u

    Confirm:

    • No general-purpose workloads appear in the list.
    • Any remaining entries are explicitly reviewed and documented as justified exceptions.
Using kubectl
# 1. List all namespaces
# Run on: any machine with kubectl access
kubectl get ns -o name

Problem indication: None yet; this is just to scope the review.


# 2. List all PodSecurityPolicy objects (if the API is enabled)
# Run on: any machine with kubectl access
kubectl get podsecuritypolicy.policy -o yaml

Problem indication:

  • PSPs missing requiredDropCapabilities completely.
  • PSPs with requiredDropCapabilities present but NOT including NET_RAW or ALL.

You are looking for sections like:

spec:
requiredDropCapabilities:
- NET_RAW

or

spec:
requiredDropCapabilities:
- ALL

PSPs whose requiredDropCapabilities list does not contain NET_RAW or ALL may allow containers with NET_RAW.


# 3. For each namespace, list pods and see what capabilities they actually have
# (this is evidence; enforcement is via PSP/PodSecurityPolicy-like controls)
# Run on: any machine with kubectl access

# Example: review all pods (can be large)
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}'

# For a specific namespace (replace <namespace>):
kubectl get pods -n <namespace> -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'

Then inspect individual pods:

# Show full pod spec including securityContext and capabilities
# Run for any suspicious pod
kubectl get pod <pod-name> -n <namespace> -o yaml

Problem indication in pod YAML:

  • At pod-level securityContext:
    spec:
    securityContext:
    capabilities:
    add:
    - NET_RAW
  • Or at container-level:
    spec:
    containers:
    - name: ...
    securityContext:
    capabilities:
    add:
    - NET_RAW

Any pod or container explicitly adding NET_RAW is a potential concern and requires human review to determine if it is justified.


# 4. Quickly search all pod specs for NET_RAW (evidence of usage)
# Run on: any machine with kubectl access
kubectl get pods -A -o yaml | grep -n "NET_RAW"

Problem indication:

  • Any matches show pods or containers declaring NET_RAW in their capabilities.
  • Each occurrence should be reviewed to decide whether NET_RAW is truly required.

# 5. Check for namespace-level Pod Security (if applicable) that might allow NET_RAW
# Run on: any machine with kubectl access
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.metadata.labels}{"\n"}{end}'

Problem indication:

  • Namespaces labeled with privileged or unrestricted policies (for example, pod-security.kubernetes.io/enforce=privileged or similar) can make it easier for workloads to use NET_RAW without restriction.
  • These namespaces require closer review of workloads using the checks above.

Use these commands to collect evidence. Determining whether and where to forbid NET_RAW (e.g. via PodSecurityPolicy or other admission controls) requires human judgment based on application needs and acceptable risk.

Automation
#!/usr/bin/env bash
# Report pods/containers that can use NET_RAW capability (add or not dropped)

set -euo pipefail

# REQUIREMENTS:
# - Run on any machine with kubectl access and correct KUBECONFIG
# - kubectl 1.14+ with JSONPath support

echo "=== Scanning all pods/containers for NET_RAW capability exposure ===" >&2

# 1. List pods that explicitly ADD NET_RAW in securityContext.capabilities.add
echo
echo "== Pods with containers that explicitly ADD NET_RAW =="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers + (.spec.initContainers // []))
| map(
{
name: .name,
addCaps: (.securityContext.capabilities.add // [] | map(. // ""))
}
)
)
}
| {
ns,
pod,
containers: (
.containers
| map(select(.addCaps | index("NET_RAW")))
)
}
| select(.containers | length > 0)
| [
"NAMESPACE=" + .ns,
"POD=" + .pod,
"CONTAINER(S)=" + (.containers | map(.name) | join(",")),
"ADDED_CAPS=" + (.containers | map(.addCaps | join(",")) | join(" | "))
]
| join(" | ")
' 2>/dev/null || {
echo "ERROR: This script requires 'jq' on PATH." >&2
exit 1
}

# 2. List pods where NET_RAW is NOT in drop list and there is some capability use
# This surfaces containers that might retain NET_RAW by omission
echo
echo "== Pods with capabilities configured but NET_RAW is NOT in drop list =="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
(.spec.containers + (.spec.initContainers // []))
| map(
{
name: .name,
addCaps: (.securityContext.capabilities.add // [] | map(. // "")),
dropCaps: (.securityContext.capabilities.drop // [] | map(. // ""))
}
)
)
}
| {
ns,
pod,
containers: (
.containers
| map(
select(
# Only consider containers that touch capabilities at all
((.addCaps | length) > 0 or (.dropCaps | length) > 0)
# AND do not explicitly drop NET_RAW nor ALL
and ((.dropCaps | index("NET_RAW")) | not)
and ((.dropCaps | index("ALL")) | not)
)
)
)
}
| select(.containers | length > 0)
| [
"NAMESPACE=" + .ns,
"POD=" + .pod,
"CONTAINER(S)=" + (.containers | map(.name) | join(",")),
"ADD_CAPS=" + (.containers | map(.addCaps | join(",")) | join(" | ")),
"DROP_CAPS=" + (.containers | map(.dropCaps | join(",")) | join(" | "))
]
| join(" | ")
'

# 3. (Optional) List any PodSecurityPolicies that DO NOT drop NET_RAW or ALL
# Only relevant if PSP is still enabled in your cluster
echo
echo "== PodSecurityPolicies that do NOT require dropping NET_RAW or ALL (if PSP is enabled) =="
if kubectl get podsecuritypolicies.policy >/dev/null 2>&1; then
kubectl get podsecuritypolicies.policy -o json \
| jq -r '
.items[]
| {
name: .metadata.name,
drop: (.spec.requiredDropCapabilities // [] | map(. // ""))
}
| select(
# PSPs that do NOT include NET_RAW and do NOT include ALL
((.drop | index("NET_RAW")) | not)
and ((.drop | index("ALL")) | not)
)
| "PSP=" + .name + " | requiredDropCapabilities=" + (.drop | join(","))
'
else
echo "No PodSecurityPolicies found or PSP API disabled; skip PSP check." >&2
fi

echo
echo "=== Interpretation ==="
cat <<'EOF'
- Any line under "Pods with containers that explicitly ADD NET_RAW" indicates a clear problem:
those containers are explicitly granted the NET_RAW capability.

- Any line under
"Pods with capabilities configured but NET_RAW is NOT in drop list"
is a potential problem:
these containers manipulate capabilities but do not explicitly drop NET_RAW
(or ALL), so you must review if their effective capabilities include NET_RAW.

- Any PSP listed under
"PodSecurityPolicies that do NOT require dropping NET_RAW or ALL"
should be reviewed: benchmark guidance expects requiredDropCapabilities
to include NET_RAW or ALL.

This script does NOT automatically fix anything; use it to identify and review
workloads and policies that might violate the requirement to drop NET_RAW.
EOF

Additional Reading: