Last modified June 8, 2023
Limiting pod communication with network policies
You can limit communication to Pods using the Network Policy API of Kubernetes.
The Kubernetes Network Policy functionality is implemented by different network providers, like Calico, Cilium, Kube-router, etc. Most of these providers have some added functionality that extends the main Kubernetes Network Policy API. Giant Swarm deploys Calico as a provider so users can make use of its functionality out of the box.
In this guide we give an overview and introduction of how to create and use these policies.
Network Policies Scope
By default, all Pods in a cluster are non-isolated and accept traffic from any source.
As soon as you have a NetworkPolicy that selects a certain group of Pods, those Pods become isolated and reject any traffic that is not allowed by any NetworkPolicy.
Note that Network Policies are additive, so having two Network Policies that select the same Pods will result in allowing both defined policies.
Keep in mind that a NetworkPolicy is applied to a particular Namespace and only selects Pods in that particular Namespace.
Network Policy syntax
The Network Policy resource is part of the API group networking.k8s.io
. Currently, it is in version v1
.
The spec
of the resource mainly consists of three parts:
podSelector
: Use labels to select the group of pods for which the rules will be applied.policyTypes
: Which could beIngress
,Egress
or both. This field will determine if the rules will be applied to incoming and/or outgoing traffic. If it is not defined, thenIngress
will be enabled by default andEgress
only when there are rules defined.ingress
/egress
: these sections allow a list offrom
(Ingress) orto
(Egress) andports
blocks. Eachfrom
/to
block contains a range of IPs (ipBlock
) and/or a list of namespaces selected by label (namespaceSelector
) and/or a list of pods by label (podSelector
). That select which IPs, namespaces or pods can talk to our target pod or to which IPs, namespaces or pod our target can talk to. Theports
block defines which ports are affected by this the rule.
An easy example to clarify the explained concepts
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: simple-policy
namespace: default
spec:
podSelector:
matchLabels:
app: target-app-who-is-applied-the-policy
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
- namespaceSelector:
matchLabels:
name: namespace-that-can-talk-to-my-app
- podSelector:
matchLabels:
app: pod-that-can-talk-to-my-app
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
- namespaceSelector:
matchLabels:
name: namespace-my-app-can-talk-to
- podSelector:
matchLabels:
app: pod-my-app-can-talk-to
ports:
- protocol: TCP
port: 5978
Default policies
You can create default policies for a namespace by creating a NetworkPolicy that selects all Pods as follows:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Warning: By default Giant Swarm clusters, from version 11.0.0
, contain a default-deny
policy for sensitive namespaces like giantswarm
and kube-system
. To communicate with any pods in that namespace you need to explicitly create a Network Policy that allows it.
Note that the namespace needs to exist before you apply the NetworkPolicy to it.
The default policy shown above will limit ingress and egress traffic in the namespace applied. You can also restrict only for egress
or ingress
.
Applications
Allowing specific system pod to talk with your pod
As we mentioned before, we harden the clusters restricting the communication with pods in kube-system
and giantswarm
. In case you need to allow communication with a running pod in one of those namespaces you have to explicitly declare it. For example:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: ksm-can-be-accessed-by-my-app
namespace: kube-system
spec:
podSelector:
matchLabels:
app: kube-state-metrics
ingress:
- from:
- podSelector:
matchLabels:
app: my-app-that-needs-access-to-ksm
ports:
- protocol: TCP
port: 10301
To make it more visual, this is what the communication between namespaces will look like.
Allowing specific pod to pod access
In the following example, we allow traffic to Pods labeled role: backend
from Pods with the role: frontend
label and only on TCP port 6379.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: backend-access
spec:
podSelector:
matchLabels:
role: backend
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
You need to apply this policy to the Namespace that the backend Pods live in.
kubectl -n <namespace> apply -f backend-access.yaml
Allowing pod to pod access within a namespace
In some cases, you may want to allow all intra-namespace communication. For this, you can use open Pod selectors that catch all Pods.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: intra-namespace
namespace: freeforall
spec:
podSelector:
ingress:
- from:
- namespaceSelector:
matchLabels:
name: freeforall
Note that the namespace you apply this policy to needs to carry a label name:
similar to the actual name key in its metadata:
apiVersion: v1
kind: Namespace
metadata:
name: freeforall
labels:
name: freeforall
After creating the namespace, you can then create the NetworkPolicy
.
kubectl apply -f freeforall-namespace.yaml
kubectl apply -f intra-namespace-policy.yaml
Allowing traffic from outside the cluster
In case you have publicly exposed a Service through Ingress and you have a default-deny policy in place or just want to limit that traffic to a specific port, you need a Network Policy like the following.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-external
namespace: default
spec:
podSelector:
matchLabels:
app: web
ingress:
- from: []
ports:
- port: 80
The allow-external
policy, described above, will allow any traffic (no matter if it’s outside or inside your cluster) to the Pods on port 80.
In this guide we discussed different use-cases of limiting Pod communication with network policies, based on our best practices.
Allowing DNS traffic from my pod
Once you have a default deny egress policy, the DNS traffic is also blocked. When you want to allow egress traffic for a specific application then you will need to allow DNS traffic too. You can use a NetworkPolicy that targets just DNS like:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-for-my-app
podSelector:
matchLabels:
app: web
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: UDP
port: 1053
Warning: By default Giant Swarm clusters run CoreDNS listening on the port 1053 (due to security reasons). So you will need to include port 1053
on the list of ports.
Further reading
Need help, got feedback?
We listen to your Slack support channel. You can also reach us at support@giantswarm.io. And of course, we welcome your pull requests!