KubernetesXLIV · NetworkPolicyNetworkPolicy
Default-deny policies — the zero-trust pattern
What you'll learn
- Implement the default-deny pattern in a namespace
- Add the DNS and API allow rules for the default-deny
- Identify the failure modes of default-deny
- Apply the operational discipline of using default-deny in production
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The default-deny pattern is the basis of zero-trust networking. The pattern denies all traffic by default and allows only the explicit allow rules. This lesson walks the default-deny pattern, the implementation, and the operational discipline.
The default-deny pattern
The default-deny pattern is the production standard for NetworkPolicy. The pattern has three parts:
- Default-deny: deny all traffic by default.
- DNS allow: allow DNS resolution to the kube-dns Service.
- API allow: allow API server access for the Pods that need it.
flowchart LR
A[Default-deny] --> B[All traffic blocked]
B --> C[DNS allow]
B --> D[API allow]
B --> E[Internal allow]
C --> F[Allowed traffic]
D --> F
E --> F
The default-deny is the foundation. The allow rules are the exceptions.
The default-deny ingress
The default-deny ingress blocks all inbound traffic:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-app-default-deny-ingress
namespace: prod-app
spec:
podSelector: {}
policyTypes:
- Ingress
The podSelector: {} matches every Pod in the
namespace. The policyTypes: Ingress declares ingress
deny. The result is that every Pod in the namespace
has no ingress by default.
The default-deny egress
The default-deny egress blocks all outbound traffic:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-app-default-deny-egress
namespace: prod-app
spec:
podSelector: {}
policyTypes:
- Egress
The podSelector: {} matches every Pod in the
namespace. The policyTypes: Egress declares egress
deny. The result is that every Pod in the namespace
has no egress by default.
The DNS allow rule
The DNS allow rule allows DNS resolution:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-app-allow-dns
namespace: prod-app
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: 53
The DNS allow rule allows TCP and UDP port 53 to the kube-dns Service. Without this rule, the Pods cannot resolve DNS names.
The API allow rule
The API allow rule allows API server access:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-app-allow-api
namespace: prod-app
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.96.0.1/32
ports:
- protocol: TCP
port: 443
The API allow rule allows TCP 443 to the API server’s
IP. The API server’s IP is the
kubernetes.default.svc.cluster.local ClusterIP.
The internal allow rules
The internal allow rules allow traffic between Pods:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prod-app-allow-internal
namespace: prod-app
spec:
podSelector:
matchLabels:
app: billing
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api-gateway
ports:
- protocol: TCP
port: 8080
The internal allow rule allows traffic from the api-gateway to the billing Pods.
The failure modes
The default-deny’s failure modes:
- DNS rule missing: the Pods cannot resolve DNS. The fix is to add the DNS allow rule.
- API rule missing: the Pods cannot authenticate to the API server. The fix is to add the API allow rule.
- Internal rule missing: the Pods cannot communicate internally. The fix is to add the internal allow rules.
- Selector mismatch: the selector does not match the intended Pods. The fix is to verify the selectors.
The operational discipline
The default-deny’s operational discipline:
- Document the default-deny. The default-deny is the cluster’s firewall configuration.
- Audit the default-deny at every change. The default-deny is critical security configuration.
- Test the default-deny in staging. The default-deny must work for the workload.
- Use the default-deny pattern. The default-deny is the basis of zero-trust.
- Plan the default-deny’s evolution. The default-deny can be extended with CNI-specific resources.
- Document the troubleshooting. The troubleshooting is the cluster’s operational reference.
Quiz
Knowledge check · 4 questions
Q1. What is the default-deny pattern in NetworkPolicy?
Q2. The default-deny pattern requires explicit allow rules for DNS and API server access.
Q3. The default-deny pattern is applied. The Pods cannot resolve DNS. The DNS allow rule is missing. What is the diagnostic flow and the recovery?
The cluster has a default-deny pattern. The Pods cannot resolve DNS. The DNS allow rule is missing. The cluster operator must investigate.
Q4. Name two allow rules that must be added to a default-deny pattern.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- The default-deny pattern is the production standard. The cluster operator must use the default-deny pattern.
- Document the default-deny. The default-deny is the cluster’s firewall configuration.
- Audit the default-deny at every change. The default-deny is critical security configuration.
- Test the default-deny in staging. The default-deny must work for the workload.
- Use the default-deny pattern. The default-deny is the basis of zero-trust.
- Plan the default-deny’s evolution. The default-deny can be extended with CNI-specific resources.
- Document the troubleshooting. The troubleshooting is the cluster’s operational reference.
- Train the security team on the default-deny. The default-deny is the basis of the cluster’s security.
- Use a CI check for the default-deny. The CI check can catch the default-deny violation at every change.