Kubernetes how-to
Kubernetes Network Policy: Default Deny With Examples
A NetworkPolicy selects pods and controls the traffic allowed to and from them. Without any policy selecting a pod, all traffic is allowed. Once a policy selects a pod for ingress or egress, only the traffic that policy allows gets through. Policies only take effect if the cluster network plugin enforces them.
By Muhammad Soliman, Founder at SeaGit
·
Key takeaways
- A policy with an empty podSelector selects every pod in its namespace. A default-deny policy is a policy with no allow rules for the chosen direction.
- Creating a NetworkPolicy does nothing unless the network plugin implements it. The official page says so directly.
- Default-deny egress also blocks DNS. Allow UDP and TCP port 53 to the cluster DNS, or every name lookup fails.
- On EKS with the VPC CNI network policy agent, standard mode lets a new pod run with a default-allow policy until its policies arrive. Strict mode starts it denied.
How the selection and the defaults work
The NetworkPolicy resource has a podSelector, which picks the pods the policy applies to, and policyTypes, which says whether the policy governs ingress, egress or both. The official docs describe the two default shapes: a policy that allows all egress from the selected pods, and a default-deny ingress policy that selects every pod.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: prod
spec:
podSelector: {} # every pod in prod
policyTypes:
- Ingress # no ingress rules listed, so no ingress is allowedThe official page says this policy ensures even pods not selected by any other policy are isolated for ingress. The egress side needs its own policy.
Allow the frontend to reach the API, and nothing else
Once default-deny is in place, you open only the paths you need. This policy lets pods labelled app=frontend reach pods labelled app=api on port 8080. Everything else into the API stays blocked.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend
namespace: prod
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080Test the rule from both sides
# Should succeed: a frontend pod reaching the API
kubectl exec -n prod deploy/frontend -- wget -qO- -T 3 http://api:8080/healthz
# Should time out: a pod without the frontend label
kubectl run probe -n prod --rm -it --image=busybox:1.36 --restart=Never -- \
wget -qO- -T 3 http://api:8080/healthzThe DNS trap: default-deny egress blocks name lookups
If you deny egress, a pod can no longer reach the cluster DNS service either, and every connection that uses a name fails while IP-based calls still work. This is the most common surprise after a default-deny egress rollout. Allow DNS explicitly, to the DNS pods, on port 53.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: prod
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53EKS: the VPC CNI mode decides whether policies protect a new pod
On Amazon EKS, the Amazon VPC CNI plugin includes a network policy agent. Its README describes two modes that change what a new pod does while its policies are still being applied. In standard mode, the pod starts with a default-allow policy, and all ingress and egress is allowed until its policies are configured. In strict mode, the pod starts with a default-deny policy and nothing is allowed until policies exist.
- Standard mode: a brief window at pod start where policies are not yet enforced. Fine for most workloads, but a security gap if it matters.
- Strict mode: no window, but every pod needs a policy or it cannot talk. Host-network pods are exempt, according to the README.
- Check the setting on your cluster before you rely on policies. A policy that is never applied gives no protection, even when it looks correct.
# Confirm the network policy agent is present in the aws-node DaemonSet
kubectl get daemonset aws-node -n kube-system \
-o jsonpath='{.spec.template.spec.containers[*].name}'
# List policies and what they select
kubectl get networkpolicy -n prod
kubectl describe networkpolicy api-allow-frontend -n prodDebugging a policy that blocks too much
Policies are easy to get wrong because a missing rule looks like an application fault. Work through the checks in order: is the plugin enforcing policies, does the selector match the pod labels, and is the port the one the app really listens on.
- Selector mismatch: kubectl get pods -n prod --show-labels against the policy podSelector. Labels are exact.
- Wrong direction: an allow on ingress does not open egress from the same pod. Add the policyType you need.
- Port: the policy lists the container port. A Service port that maps to a different target port is a common mismatch.