This episode dissects Calico's namespaced NetworkPolicy: selector structure, ingress and egress, ports and protocols, the default deny principle, and the order of policy evaluation using tiers.

This is the episode that most often gets people to adopt Calico: network policy. In this episode you learn to write policies that control traffic in and out of workloads based on labels, ports, and protocols — and more importantly, you understand when a packet is allowed or denied.
The ground rules must be clear from the start: in Calico, the default is allow. If no policy matches a workload, all traffic flows freely. To build real security, you must close that gap with a default deny policy — a theme we dig deeper into in episode 13.
Calico provides a NetworkPolicy with the projectcalico.org/v3 apiVersion. Syntactically it's similar to networking.k8s.io/v1, but with advantages: selectors use Calico labels, explicit actions (Allow/Deny/Pass/Log), and broader protocol support such as SCTP.
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-web-from-app
namespace: default
spec:
selector: app == 'web'
types:
- Ingress
ingress:
- action: Allow
protocol: TCP
source:
selector: app == 'app'
destination:
ports:
- 8080This policy allows pods labeled app: web to receive TCP from pods labeled app: app on port 8080. Notice action: Allow — in Calico the action is explicit, not just adding a rule.
Selectors can reach across namespaces with namespaceSelector:
source:
namespaceSelector: project == 'frontend'
selector: app == 'api-client'The combination of namespaceSelector and selector means: pods from namespaces matching the label project: frontend and labeled app: api-client.
As long as no policy exists, kubectl exec and cross-namespace access run freely. To change that, create a policy that matches the workload and has no Allow rules:
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: default-deny-web
namespace: default
spec:
selector: app == 'web'
types:
- Ingress
- Egress
ingress: []
egress: []A policy with ingress: [] and egress: [] means: all traffic not matched by another rule will be denied for this workload. This is the basic microsegmentation pattern.
When a pod is matched by several policies, the rules from all policies are combined and evaluated in order by tiers (episode 6). The first matching rule determines the action. That's why rule order matters: put a more specific deny before a broad allow.
Verify the policies applied to a specific workload:
calicoctl get networkpolicy -n default -o yaml
calicoctl get workloadendpoints -n default
kubectl describe networkpolicy -n defaultkubectl describe networkpolicy shows a summary of the rules attached to a specific pod — useful when a policy seems to have no effect.
Besides ingress, you can restrict outbound traffic. For example, a client pod may only exit to port 443:
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: egress-client
namespace: default
spec:
selector: app == 'client'
types:
- Egress
egress:
- action: Allow
protocol: TCP
destination:
selector: app == 'api'
ports:
- 443Remember: egress also needs DNS permission. If a workload must resolve names, add a rule for CoreDNS (we cover this in detail in episode 11).
Rule protocols support TCP, UDP, SCTP, and ICMP. For port ranges:
destination:
ports:
- 9000
- 10000:1100010000:11000 means ports 10000 through 11000. protocol and ports must always be paired together.
After applying the policy, test it with pods on both sides:
kubectl run allow-src --image=busybox --labels app=app --command -- sleep 3600
kubectl run deny-src --image=busybox --labels app=other --command -- sleep 3600
kubectl exec allow-src -- wget -q -O - http://web.default.svc.cluster.local:8080
kubectl exec deny-src -- wget -q -O - http://web.default.svc.cluster.local:8080The allow-src pod should succeed, while deny-src will time out because it isn't matched by an Allow policy. If deny-src actually succeeds, there's an allow policy that's too broad — or the policy hasn't been applied.
Episode 5 equips you with Calico's core security skills: writing namespaced NetworkPolicies, understanding the default deny principle, controlling ingress and egress, and testing the real effect of policies.
Key takeaways:
action is explicit: Allow, Deny, Pass, and Log.namespaceSelector for cross-namespace matching.start:end format.kubectl describe networkpolicy and pod tests are the fastest way to validate.In the next episode, episode 6, we go up a level: GlobalNetworkPolicy and tiers — cluster-scoped policy that applies to all nodes, GlobalNetworkSet, and the security, platform, and application tier hierarchy that governs the order of policy evaluation across the whole cluster.