RAPID INCIDENT TRIAGE & ACTION PLAN•Security
01. Error Signature
NetworkPolicy Cross-Namespace Egress Monitor
02. Root Cause Vector

A Kubernetes NetworkPolicy is blocking egress traffic between namespaces, silently dropping packets and breaking cross-namespace service ...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Security

NetworkPolicy Cross-Namespace Egress Monitor

A Kubernetes NetworkPolicy is blocking egress traffic between namespaces, silently dropping packets and breaking cross-namespace service communication.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(74L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: legacy-pci-egress-lockdown
  namespace: pci-secure-zone
  annotations:
    owner: "team-legacy@my-registry.internal"
    # TODO: Review this after Q4 migration to new VPC
    # FIXME: This conflicts with the new 'data-lake-access' policy, but PCI audit requires it.
spec:
  podSelector:
    matchLabels:
      app: legacy-payment-processor
  policyTypes:
  - Egress
  egress:
  # Allow egress to internal legacy API ONLY
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: legacy-api-namespace
    ports:
    - protocol: TCP
      port: 8443
  # VULNERABILITY: This default-deny all egress rule is overridden by a global policy in 'kube-system' that allows certain monitoring traffic, but the podSelector here is too restrictive and implicitly denies egress to the required 'audit-log-aggregator' namespace due to label mismatch.
  - {}  # This empty rule DENIES ALL other egress traffic
---
# This is a leftover from the old Helm chart, probably not applied anymore
# but kept for 'reference'. The new policy above should handle it.
# apiVersion: networking.k8s.io/v1
# kind: NetworkPolicy
# metadata:
#   name: allow-monitoring
#   namespace: pci-secure-zone
# spec:
#   podSelector: {}
#   egress:
#   - to:
#     - namespaceSelector:
#         matchLabels:
#           purpose: monitoring

---
apiVersion: v1
kind: Secret
metadata:
  name: legacy-aws-creds
  namespace: pci-secure-zone
type: Opaque
data:
  aws_access_key_id: QUtJQUpFTExFR0FEWUtFWVNFQ1JFVDEyMzQ=  # AKIAJELLEGADYKEYSECRET1234 (dummy)
  aws_secret_access_key: dGhpc2lzYXN1cGVyc2VjcmV0a2V5Zm9yYXdzYWNjZXNzMTIzNDU2Nzg5MA==  # thisisasupersecretkeyforawsaccess1234567890 (dummy)
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: legacy-api-namespace
data:
  stripe.api.key: "sk_live_thisisadummystripeapikey1234567890abcdef"
  database.uri: "postgresql://legacy_user:SuperSecretDBP@ssw0rd!@old-db.internal:5432/legacy_payments?sslmode=require"
  # TODO: Rotate this RSA key after migration
  ssh_private_key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAtDummyKeyDataForSSHKeyExample1234567890abcdefghijklmnopqrstuvwxyz
    ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
    QRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345
    6789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklm
    nopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCD
    EFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU
    VWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ab
    cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrs
    -----END RSA PRIVATE KEY-----
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

Fixing 'Egress Traffic Denied by NetworkPolicy' Between Kubernetes Namespaces

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10–20 mins

TL;DR

  • What broke: A NetworkPolicy with no egress block (or a misconfigured namespaceSelector) is silently dropping all outbound traffic from your pods to another namespace.
  • How to fix it: Add an explicit egress rule with the correct namespaceSelector matching the destination namespace's labels, plus the required ports block.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor this — paste your failing NetworkPolicy YAML and get a corrected version without sending your config to any external server.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

You'll see this surface in pod logs, curl timeouts, or via a service mesh like Istio/Linkerd as:

Error: dial tcp <ClusterIP>:<port>: i/o timeout
# or from a CNI like Calico:
EGRESS traffic denied by NetworkPolicy: source=<pod> destination=<namespace>/<service>

Kubernetes NetworkPolicy is default-deny by omission. The moment you attach any NetworkPolicy to a pod, all traffic not explicitly permitted is dropped — including egress. If your policy has an ingress block but no egress block, every outbound packet from that pod is silently killed. No ICMP unreachable. No RST. Just a timeout.

Immediate consequence: Any pod selected by this policy cannot reach services in other namespaces — databases, auth services, external APIs routed through a gateway namespace. This is a full service communication blackout.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is a misconfiguration-as-outage pattern. The blast radius depends on how broadly the podSelector is scoped:

  • If podSelector: {} (matches all pods in namespace) — entire namespace is egress-isolated. Every microservice calling a dependency in another namespace fails simultaneously.
  • Cascading failure path: frontend → can't reach auth-service (different namespace) → returns 500 → circuit breaker trips → frontend marks itself unhealthy → load balancer pulls it → full service outage.
  • In a zero-trust posture, this is intended behavior applied at the wrong scope. The danger is that developers add a NetworkPolicy for ingress hardening and unknowingly nuke all egress without realizing NetworkPolicy is additive-only and non-reversible without an explicit allow rule.
  • DNS is the first casualty. kube-dns lives in kube-system. If your egress policy doesn't explicitly allow UDP/TCP 53 to kube-system, DNS resolution fails before any application-level connection is even attempted. This makes the error appear as a generic connection failure, masking the real cause.

How to Fix It (The Solution)

Basic Fix — Add Egress Rule for Target Namespace

First, confirm the destination namespace has the correct label:

kubectl get namespace target-namespace --show-labels
# Must show a label you can match, e.g.: kubernetes.io/metadata.name=target-namespace

Then patch your NetworkPolicy:

 apiVersion: networking.k8s.io/v1
 kind: NetworkPolicy
 metadata:
   name: app-network-policy
   namespace: source-namespace
 spec:
   podSelector:
     matchLabels:
       app: my-service
   policyTypes:
     - Ingress
+    - Egress
   ingress:
     - from:
         - podSelector:
             matchLabels:
               app: allowed-client
+  egress:
+    - to:
+        - namespaceSelector:
+            matchLabels:
+              kubernetes.io/metadata.name: target-namespace
+      ports:
+        - protocol: TCP
+          port: 8080
+    - to:
+        - namespaceSelector:
+            matchLabels:
+              kubernetes.io/metadata.name: kube-system
+      ports:
+        - protocol: UDP
+          port: 53
+        - protocol: TCP
+          port: 53

Do not forget the DNS egress rule. Skipping it means your pods resolve nothing, and the real NetworkPolicy error gets buried under DNS timeout noise.


Enterprise Best Practice — Least-Privilege Egress with Combined Selectors

Using only namespaceSelector is too broad if the target namespace runs multiple services. Combine namespaceSelector + podSelector to pin egress to the exact target pods:

  egress:
-    - to:
-        - namespaceSelector:
-            matchLabels:
-              kubernetes.io/metadata.name: target-namespace
-      ports:
-        - protocol: TCP
-          port: 8080
+    - to:
+        - namespaceSelector:
+            matchLabels:
+              kubernetes.io/metadata.name: target-namespace
+          podSelector:
+            matchLabels:
+              app: payment-service
+              tier: backend
+      ports:
+        - protocol: TCP
+          port: 8080

Critical: When namespaceSelector and podSelector are under the same - list item (same to entry), Kubernetes evaluates them as AND (intersection). If you put them as separate - entries, it's OR (union) — which is almost always too permissive. This YAML indentation distinction is the #1 source of NetworkPolicy bugs in production.


💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. OPA/Gatekeeper — Enforce egress DNS rule presence:

Write a Rego policy that rejects any NetworkPolicy with policyTypes containing Egress but no egress rule targeting port 53. Gate this in your admission webhook.

2. Checkov scan in pipeline:

checkov -f networkpolicy.yaml --check CKV_K8S_7
# CKV_K8S_7: Ensure NetworkPolicy is not overly permissive

Add custom Checkov checks for missing DNS egress rules — the built-in checks don't catch this by default.

3. Kyverno policy — Require namespace labels before NetworkPolicy references them:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-ns-label-for-egress
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-namespaceselector-label
      match:
        resources:
          kinds: [NetworkPolicy]
      validate:
        message: "Egress namespaceSelector must use kubernetes.io/metadata.name label."
        pattern:
          spec:
            egress:
              - to:
                  - namespaceSelector:
                      matchLabels:
                        "kubernetes.io/metadata.name": "?*"

4. Automated integration test: Run a netpol-tester job (e.g., networkpolicy-viewer or cyclonus) as a post-deploy step in staging. It enumerates all NetworkPolicies and validates actual pod-to-pod reachability against declared intent. Fail the pipeline if reachability matrix diverges from spec.

5. Label hygiene: Enforce via CI that every namespace has kubernetes.io/metadata.name set (it's auto-set in K8s 1.21+, but custom labels used in selectors must be validated to exist before the policy is applied).

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does adding any NetworkPolicy break all egress traffic even if I only defined ingress rules?
Kubernetes NetworkPolicy is additive and default-deny per policy type. The moment you include 'Egress' in policyTypes — or in some CNI implementations, simply create any NetworkPolicy targeting a pod — all egress not explicitly permitted is dropped. If your policy only defines ingress rules but lists 'Egress' in policyTypes, there are zero permitted egress destinations, so all outbound traffic is silently discarded. This is a foundational design flaw that turns a simple intent into a production outage.
Q2.Why does cross-namespace egress fail even after I add an egress rule — DNS resolution is broken?
DNS queries go to kube-dns in the kube-system namespace on UDP/TCP port 53. If your egress policy doesn't include an explicit rule allowing traffic to kube-system on port 53, all DNS resolution fails. The application then reports a generic connection timeout instead of a NetworkPolicy denial, masking the real cause. Manually patching this is a high-risk game of whack-a-mole; one missed namespace or port creates a silent, untraceable outage. Drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix with guaranteed DNS egress rules, eliminating the blast radius of human error.
Q3.What is the difference between namespaceSelector and podSelector being in the same 'to' entry versus separate entries?
This is the most dangerous YAML indentation bug in NetworkPolicy. When namespaceSelector and podSelector are under the same '-' list item in a 'to' block, Kubernetes evaluates them as AND — traffic must match both the namespace AND the pod label. When they are separate '-' list items, it's OR — traffic matching either condition is allowed. Using separate entries when you intend AND creates an overly permissive policy that allows egress to all pods in the target namespace OR all pods with that label in any namespace, creating a massive compliance and security gap. At enterprise scale, manually auditing thousands of policies for this single indentation error is a compliance nightmare. Deploy the StackEngine CI/CD Automator (Team Edition) for on-prem, automated pull request generation with Maker-Checker review that enforces intent across your entire mono-repo before deployment.