Ingress-Only NetworkPolicy Leaves Kubernetes Egress Open
Kubernetes NetworkPolicy objects only restrict the traffic direction named in policyTypes. Learn to detect, fix and validate the common Ingress-only trap that leaves Egress fully open.
Operational summary
At a glance
- Symptom
- A workload that is meant to be network-isolated after applying a NetworkPolicy still reaches services and endpoints outside its expected boundary, and the outbound…
- Likely cause
- The root cause is an incomplete policyTypes declaration combined with the platform's default-allow networking model.Kubernetes documents NetworkPolicy as part of its wider set of…
- Impact
- The workload appears protected in dashboards and change records while retaining an open path for lateral movement, data exfiltration or unintended dependency calls.This is material for workloads handling…
- Verification signal
- Validation passes only when the previously open outbound path is now blocked and every required egress destination still succeeds.Repeat the earlier outbound test to the endpoint that should…
- Safe correction
- Add an explicit Egress entry to policyTypes together with the specific egress rules the workload actually needs, then re-test before relying on the change.apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata…
- Rollback or recovery
- Rollback removes the new egress restriction immediately if a required destination was missed and the workload starts failing.kubectl delete -f allow-ingress-and-restrict-egress.yaml -n workload-ns Keep the previous ingress-only policy…
Symptom
A workload that is meant to be network-isolated after applying a NetworkPolicy still reaches services and endpoints outside its expected boundary, and the outbound traffic is usually noticed during an unrelated security review rather than at deployment time.
Engineers report that a NetworkPolicy is already applied to the pod, while packet captures, service mesh logs or firewall alerts show the pod initiating connections the policy was supposed to prevent.
False Assumption
The team assumes that creating any NetworkPolicy object that selects a pod automatically switches that pod into a fully isolated, default-deny state for both inbound and outbound traffic.
In practice, a NetworkPolicy only restricts the traffic direction listed in its policyTypes field. A policy that lists only Ingress leaves egress completely unaffected, because Kubernetes’ default network model permits all traffic in any direction not covered by a matching policy.
Root Cause
The root cause is an incomplete policyTypes declaration combined with the platform’s default-allow networking model.
Kubernetes documents NetworkPolicy as part of its wider set of workload, authentication, authorisation and policy controls. Within that model, a Pod with no matching NetworkPolicy remains fully open in all directions. Once any policy selects that Pod, only the traffic types explicitly named in policyTypes become restricted; unnamed directions stay exactly as open as before the policy existed.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-only
namespace: workload-ns
spec:
podSelector:
matchLabels:
app: payments-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
This policy legitimately restricts inbound traffic to the payments-api pods, but because policyTypes omits Egress, every outbound connection from those pods remains unrestricted, including to endpoints outside the cluster if the CNI plugin allows external egress by default.
Impact
The workload appears protected in dashboards and change records while retaining an open path for lateral movement, data exfiltration or unintended dependency calls.
This is material for workloads handling sensitive data, because a reviewer who only checks whether a NetworkPolicy exists will record false assurance instead of validating what the policy actually restricts.
Diagnosis
Confirm the trap by reading the policy’s declared types before testing live traffic.
- List every NetworkPolicy in the namespace and inspect
policyTypesfor each one. - Cross-check the pod’s labels against the policy’s
podSelectorto confirm the policy actually matches the workload. - From a test pod with the same labels, attempt an outbound connection to a service that should be blocked, and record whether it succeeds.
kubectl get networkpolicy -n workload-ns -o yaml
kubectl describe pod payments-api-xyz -n workload-ns
kubectl exec payments-api-xyz -n workload-ns -- curl -m 3 http://database.workload-ns.svc.cluster.local:5432
If the connection succeeds despite an expectation of isolation, and the listed policy’s policyTypes omits Egress, the trap is confirmed.
Correction
Add an explicit Egress entry to policyTypes together with the specific egress rules the workload actually needs, then re-test before relying on the change.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-and-restrict-egress
namespace: workload-ns
spec:
podSelector:
matchLabels:
app: payments-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
egress:
- to:
- podSelector:
matchLabels:
role: database
ports:
- protocol: TCP
port: 5432
Apply this only in an isolated or non-production namespace first, and confirm every required egress destination (DNS, database, monitoring agents) is listed before enforcing it against a live workload, since an incomplete egress list will break legitimate traffic rather than only close the gap.
kubectl apply -f allow-ingress-and-restrict-egress.yaml -n workload-ns
Validation
Validation passes only when the previously open outbound path is now blocked and every required egress destination still succeeds.
- Repeat the earlier outbound test to the endpoint that should now be blocked; it must fail or time out.
- Test each destination named in the new egress rules (database, DNS, monitoring) and confirm each still succeeds.
- Run
kubectl describe networkpolicy allow-ingress-and-restrict-egress -n workload-nsand confirmpolicyTypeslists bothIngressandEgress.
If the cluster’s CNI plugin does not enforce NetworkPolicy objects at all, none of these tests will show any change, which is itself diagnostic evidence that enforcement, not just definition, needs escalation to the platform team.
Rollback
Rollback removes the new egress restriction immediately if a required destination was missed and the workload starts failing.
kubectl delete -f allow-ingress-and-restrict-egress.yaml -n workload-ns
Keep the previous ingress-only policy definition on hand before making the change so it can be re-applied to restore the prior open-egress state while the missing destination is investigated, and treat that restored state as temporary rather than an accepted end point, since it reopens the original gap.
Prevention
Treat every NetworkPolicy review as a check of policyTypes first, not just of whether a policy object exists.
- Require reviewers to state, in writing, which directions (Ingress, Egress, or both) a given policy actually restricts.
- Where a namespace should be fully isolated by default, apply a baseline default-deny policy for both Ingress and Egress before layering workload-specific allow rules on top.
- Confirm, once per cluster and after any CNI change, that NetworkPolicy objects are actually enforced by testing a known-blocked connection, rather than assuming enforcement from the object’s presence alone.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
policyTypesIngressapiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-only
namespace: workload-ns
spec:
podSelector:
matchLabels:
app: payments-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontendVerify, roll back or escalate
Verify
Validation passes only when the previously open outbound path is now blocked and every required egress destination still succeeds.Repeat the earlier outbound test to the endpoint that should now be blocked; it must fail or time out.Test each destination named…
Rollback
Rollback removes the new egress restriction immediately if a required destination was missed and the workload starts failing.kubectl delete -f allow-ingress-and-restrict-egress.yaml -n workload-ns Keep the previous ingress-only policy definition on hand before making the change so it can be re-applied…
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.