Block Unnecessary Outbound Egress
Apply a default-deny egress policy so a compromised workload cannot reach arbitrary hosts on the internet.
Task
Restrict namespace egress to an allowlist of required destinations with a network policy.
When to use this
A workload is compromised and immediately reaches a command-and-control server because egress is unrestricted.
Prerequisites
- A CNI that supports network policies
- An inventory of required egress destinations
- A staging namespace to test
Steps
1. Deny all egress by default in the namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- EgressExpected output: Workloads cannot reach anything not explicitly allowed.
2. Allow only required destinations such as the database and DNS.
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: data
ports:
- protocol: TCP
port: 5432Expected output: Only the database port is reachable, matching the allowlist.
Troubleshooting
Problem
DNS breaks after default deny
Solution
Explicitly allow UDP and TCP 53 to the cluster DNS service.
Problem
Policy not enforced
Solution
Confirm the CNI actually supports network policy and that the namespace is selected.
Limitations
- Does not cover traffic outside the cluster boundaries.
- Requires an accurate destination inventory.
- Policy support varies by CNI.
What this recipe does
Restrict namespace egress to an allowlist of required destinations with a network policy.
A workload is compromised and immediately reaches a command-and-control server because egress is unrestricted.
Prerequisites
- A CNI that supports network policies
- An inventory of required egress destinations
- A staging namespace to test
Procedure
- Deny all egress by default in the namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
Expected result: Workloads cannot reach anything not explicitly allowed.
- Allow only required destinations such as the database and DNS.
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: data
ports:
- protocol: TCP
port: 5432
Expected result: Only the database port is reachable, matching the allowlist.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows the workload reaches only allowlisted destinations and a test connection to an arbitrary host times out.
Troubleshooting
DNS breaks after default deny — Explicitly allow UDP and TCP 53 to the cluster DNS service.
Policy not enforced — Confirm the CNI actually supports network policy and that the namespace is selected.
Limitations
- Does not cover traffic outside the cluster boundaries.
- Requires an accurate destination inventory.
- Policy support varies by CNI.