Skip to main content

Minimize The Admission Of Containers With The NET_RAW

More Info:

The NET_RAW capability allows crafting raw packets for spoofing and network attacks. Restrict its admission in workload namespaces.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Identify workload namespaces and existing policies

    • On any machine with kubectl access:
      kubectl get ns
      kubectl get psp --all-namespaces 2>/dev/null || echo "No PodSecurityPolicy cluster resource"
      kubectl get psp 2>/dev/null -o yaml || true
      kubectl get psp --all-namespaces -o wide 2>/dev/null || true
      kubectl get ns --show-labels
    • Decide which namespaces contain user workloads (exclude kube-system, monitoring, logging, etc. unless users run apps there).
  2. Review current use of NET_RAW in running workloads

    • On any machine with kubectl access, for each workload namespace (substitute the namespace name):
      NAMESPACE=prod
      kubectl get pods -n "$NAMESPACE" -o json \
      | jq -r '.items[]
      | .metadata.name as $p
      | .spec.containers[]?
      | select(.securityContext.capabilities.add[]? == "NET_RAW")
      | "\($p) \(.name) uses NET_RAW"' 2>/dev/null
      kubectl get pods -n "$NAMESPACE" -o json \
      | jq -r '.items[]
      | .metadata.name as $p
      | .spec.initContainers[]?
      | select(.securityContext.capabilities.add[]? == "NET_RAW")
      | "\($p) init:\(.name) uses NET_RAW"' 2>/dev/null
    • Record which applications currently rely on NET_RAW and confirm with the application owners whether it is truly required.
  3. Review admission controls that could restrict NET_RAW

    • On any machine with kubectl access:
      # Pod Security Admission (PSA) labels
      kubectl get ns --show-labels

      # Gatekeeper / Kyverno / other policy engines
      kubectl get constraints.constraints.gatekeeper.sh -A 2>/dev/null || true
      kubectl get cpolicies.kyverno.io -A 2>/dev/null || true
      kubectl get policies.policy -A 2>/dev/null || true

      # PodSecurityPolicy if still in use
      kubectl get psp -o yaml 2>/dev/null || true
    • For each mechanism you find, inspect whether it already forbids adding NET_RAW in workload namespaces (e.g., by disallowing capabilities.add or explicitly listing forbidden capabilities).
  4. Decide namespace-by-namespace policy for NET_RAW

    • For each workload namespace, make an explicit decision:
      • Forbidden: no containers should ever use NET_RAW.
      • Exception-only: NET_RAW allowed only for tightly controlled workloads.
    • Document the decision with justification (e.g., “prod namespace: NET_RAW forbidden; only network diagnostics namespace allows it”).
  5. Implement or tighten policies to enforce the decision

    • This is done by editing/adding Kubernetes policy objects (Pod Security Admission labels, Gatekeeper/Kyverno policies, or PodSecurityPolicy if present). There is no single command that applies to every cluster.
    • For the chosen mechanism, ensure policies for each workload namespace:
      • Reject pods that add NET_RAW unless they match an explicitly defined exception (e.g., label-based allowlist).
      • Apply policies to all relevant namespaces (via namespace labels, selectors, or target lists).
    • Use kubectl apply -f <policy-file>.yaml from any machine with kubectl access to create/update these policy objects.
  6. Verify that NET_RAW is effectively restricted

    • On any machine with kubectl access, in a workload namespace that should disallow NET_RAW, try to create a test pod:
      cat <<'EOF' | kubectl apply -f -
      apiVersion: v1
      kind: Pod
      metadata:
      name: net-raw-test
      namespace: prod
      spec:
      containers:
      - name: test
      image: busybox:1.36
      command: ["sleep", "3600"]
      securityContext:
      capabilities:
      add: ["NET_RAW"]
      EOF
    • Confirm that creation is rejected by the admission controls.
    • Re-run the inspection to ensure no admitted pods use NET_RAW unexpectedly:
      kubectl get pods -n prod -o json \
      | jq -r '.items[]
      | .metadata.name as $p
      | .spec.containers[]?
      | select(.securityContext.capabilities.add[]? == "NET_RAW")
      | "\($p) \(.name) uses NET_RAW"' 2>/dev/null
Using kubectl

Using kubectl

1. List all namespaces that may host user workloads

Run on: any machine with kubectl access.

kubectl get namespaces -o custom-columns=NAME:.metadata.name \
--no-headers | grep -vE '^(kube-system|kube-public|kube-node-lease)$'

What to look for:
The resulting list are candidate “user” namespaces where you should expect admission controls (Pod Security Admission, OPA/Gatekeeper, Kyverno, PSP if still used, etc.) to prevent NET_RAW.


2. Check for existing Pod-level security controls per namespace

2.1. Check Pod Security Admission labels (if PSA is in use)
kubectl get ns --show-labels | grep pod-security

Problem indication:
Namespaces used for user workloads that:

  • Have no pod-security.kubernetes.io/enforce label, or
  • Are labeled privileged or an overly permissive level,
    may allow pods with the NET_RAW capability unless another policy mechanism blocks it.

2.2. List any PodSecurityPolicies (legacy PSP clusters only)
kubectl get podsecuritypolicies.policy -o wide

Then, for each PSP:

kubectl get podsecuritypolicies.policy <psp-name> -o yaml

Problem indication:
PSPs that:

  • Do not restrict allowedCapabilities, and
  • Do not list NET_RAW under forbiddenSysctls/capabilities-like controls (or otherwise constrain capabilities),
    are likely to permit NET_RAW. Also check RBAC bindings to see which namespaces/pods can use such PSPs.

2.3. Check common policy engines (if deployed)

Gatekeeper (OPA) constraints:

kubectl get constraints.constraints.gatekeeper.sh -A
kubectl get k8spspcapabilities.constraints.gatekeeper.sh -A 2>/dev/null

Then inspect:

kubectl get k8spspcapabilities.constraints.gatekeeper.sh <constraint-name> -n <ns> -o yaml

Problem indication:

  • No constraints limiting container capabilities, or
  • Constraints that do not mention NET_RAW in disallowed capabilities, or
  • Constraints not selecting the user namespaces.

Kyverno ClusterPolicies/Policies:

kubectl get clusterpolicies.kyverno.io -o yaml
kubectl get policies.kyverno.io -A -o yaml

Problem indication:
Policies do not contain rules that deny or mutate away NET_RAW, or are not applied (via match / exclude) to user namespaces.


3. Identify pods/containers that currently request or add NET_RAW

This is evidence gathering; existing pods may be noncompliant with your intended policy.

kubectl get pods -A -o json | \
jq -r '
.items[]
| {ns: .metadata.namespace, pod: .metadata.name, spec: .spec}
| . as $pod
| ($pod.spec.containers + ($pod.spec.initContainers // []))[]
| .name as $cname
| {ns: $pod.ns, pod: $pod.pod, container: $cname, sc: .securityContext, psc: $pod.spec.securityContext}
| select(
(
(.psc.capabilities.add // []) + (.sc.capabilities.add // [])
) | index("NET_RAW")
)
| "\(.ns) \(.pod) \(.container)"'

If jq is not available:

kubectl get pods -A -o yaml | \
grep -E '^( namespace:| name:| *capabilities:| *add:| *- NET_RAW)' -n

Problem indication:
Any line(s)/entries showing containers with:

securityContext:
capabilities:
add:
- NET_RAW

either at the container level or via pod.spec.securityContext.capabilities.add. Those pods are using NET_RAW and should be reviewed to determine if the capability is truly required.


4. Check for Pod Security Standards violations (if PSA is enabled)

This does not directly “know” about NET_RAW but helps identify overly privileged pods.

kubectl auth reconcile -f /dev/null 2>&1 | grep -i 'pod-security'

If your cluster exposes PSA events via audit annotations, you can inspect a sample pod:

kubectl get pod -n <user-namespace> -o yaml <pod-name> | \
grep -i 'pod-security.kubernetes.io' -n

Problem indication:

  • Namespaces or pods not being evaluated by PSA, or
  • Pods running effectively at privileged level without other compensating policies, which makes it more likely they can use NET_RAW.

5. Optional: Dry-run admission test (non-production namespace)

Create a temporary test namespace:

kubectl create namespace net-raw-test

Apply a pod that explicitly adds NET_RAW:

cat << 'EOF' | kubectl apply --dry-run=server -f -
apiVersion: v1
kind: Pod
metadata:
name: net-raw-test-pod
namespace: net-raw-test
spec:
containers:
- name: test
image: busybox
command: ["sleep", "3600"]
securityContext:
capabilities:
add:
- NET_RAW
EOF

Problem indication:

  • If the dry-run succeeds (“pod/net-raw-test-pod created (server dry run)”), there is currently no admission control in that namespace preventing NET_RAW.
  • If the dry-run fails with a validation/admission error referring to capabilities or policies, then some control is in place; review the error text to confirm it is specifically blocking NET_RAW.

Clean up:

kubectl delete namespace net-raw-test
Automation
#!/usr/bin/env bash
# Purpose: Report pods that request or add the NET_RAW capability anywhere in the cluster.
# Runs on: any machine with kubectl access and current context pointing to the target cluster.

set -euo pipefail

# 1. List pods that explicitly ADD NET_RAW via securityContext.capabilities.add
echo "=== Pods that explicitly ADD NET_RAW capability (pod- or container-level) ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
podCapsAdd: (.spec.securityContext.capabilities.add // [] | map(select(.=="NET_RAW"))),
init: (
.spec.initContainers // [] |
map({
name: .name,
capsAdd: (.securityContext.capabilities.add // [] | map(select(.=="NET_RAW")))
}) |
map(select(.capsAdd|length>0))
),
containers: (
.spec.containers // [] |
map({
name: .name,
capsAdd: (.securityContext.capabilities.add // [] | map(select(.=="NET_RAW")))
}) |
map(select(.capsAdd|length>0))
)
}
| select(
((.podCapsAdd|length)>0)
or ((.init|length)>0)
or ((.containers|length)>0)
)
| "NAMESPACE=\(.ns) POD=\(.pod) " +
"POD_CAPS_ADD=\(.podCapsAdd) " +
"INIT_CONTAINERS=" +
(if (.init|length)>0 then (.init|map("\(.name):\(.capsAdd)")|join(",")) else "none" end) +
" CONTAINERS=" +
(if (.containers|length)>0 then (.containers|map("\(.name):\(.capsAdd)")|join(",")) else "none" end)
' | sort || echo "jq not available or no matching pods found."

echo
# 2. List pods that use privileged or broad capabilities, which may implicitly allow raw sockets
# (for review – does NOT necessarily mean NET_RAW is in use, but these are higher risk)
echo "=== Pods with privileged=true or ALL capabilities (for manual review of NET_RAW need) ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
podSC: .spec.securityContext,
init: .spec.initContainers // [],
containers: .spec.containers // []
}
| {
ns,
pod,
privileged: (
[
(.podSC.privileged // false),
(init[]?.securityContext.privileged // false),
(containers[]?.securityContext.privileged // false)
] | any
),
allCaps: (
[
(.podSC.capabilities.add // []),
(.podSC.capabilities.drop // []),
(init[]?.securityContext.capabilities.add // []),
(init[]?.securityContext.capabilities.drop // []),
(containers[]?.securityContext.capabilities.add // []),
(containers[]?.securityContext.capabilities.drop // [])
] | flatten | map(tostring) | map(ascii_upcase) | any(.=="ALL")
)
}
| select(.privileged==true or .allCaps==true)
| "NAMESPACE=\(.ns) POD=\(.pod) PRIVILEGED=\(.privileged) USES_ALL_CAPS=\(.allCaps)"
' | sort || echo "jq not available or no matching pods found."

echo
# 3. Summarize namespaces that currently admit NET_RAW (for policy targeting)
echo "=== Namespaces where any pod adds NET_RAW (target these for admission policies) ==="
kubectl get pods --all-namespaces -o json | \
jq -r '
.items[]
| select(
(
.spec.securityContext.capabilities.add // [] | index("NET_RAW")
) != null
or (
[.spec.initContainers[]?.securityContext.capabilities.add // []] | flatten | index("NET_RAW")
) != null
or (
[.spec.containers[]?.securityContext.capabilities.add // []] | flatten | index("NET_RAW")
) != null
)
| .metadata.namespace
' | sort -u || echo "jq not available or no matching namespaces found."

How to interpret the output

  • Any line under “Pods that explicitly ADD NET_RAW capability” indicates a problem for this control: those pods are being admitted with NET_RAW and should be reviewed; if not strictly required, they should be reconfigured to drop it and/or blocked by admission policy.
  • Lines under “Pods with privileged=true or ALL capabilities” are high‑risk candidates: they may effectively allow raw network operations even if NET_RAW is not explicitly listed. These require manual review to decide whether NET_RAW (or equivalent capability) is actually needed and whether to tighten security.
  • Namespaces listed under “Namespaces where any pod adds NET_RAW” are priority targets for creating or tightening admission policies (e.g., PodSecurity, PodSecurityPolicies where still in use, or external admission controllers) to restrict NET_RAW for user workloads.