post image January 17, 2022 | 4 min Read

Kubernetes network policies

Here is an example of network policies

k taint node scw-k8s-cks node-role.kubernetes.io/master-
k run frontend --image=nginx
k run backend --image=nginx
k get pods
k expose  pod frontend --port 80
k expose  pod backend --port 80
k get svc

If pods has more “network policies” - all of them will be merged.

Default deny network policy

root@scw-k8s-cks:~# cat default-deny.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-policy
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

# connection does not work anymore
root@scw-k8s-cks:~# k exec frontend -- curl backend
root@scw-k8s-cks:~# k exec backend -- curl frontend

Setting up following network policies

There are two pods currently running at your cluster

root@scw-k8s-cks:~# k get pods
NAME       READY   STATUS    RESTARTS   AGE
backend    1/1     Running   0          4h27m
frontend   1/1     Running   0          4h30m

Frontend part

root@scw-k8s-cks:~# cat allow-frontend-to-talk-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-talk-to-backend
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: frontend
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          run: backend
    ports:
    - protocol: TCP
      port: 80

Backend part

root@scw-k8s-cks:~# cat backend-to-frontend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-to-frontend
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: frontend
    ports:
    - protocol: TCP
      port: 80

Now check wheter we can connect from frontend -> backend

root@scw-k8s-cks:~# k get pods -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
backend    1/1     Running   0          23h   10.32.0.5   scw-k8s-cks   <none>           <none>
frontend   1/1     Running   0          23h   10.32.0.4   scw-k8s-cks   <none>           <none>
root@scw-k8s-cks:~# k exec -it frontend -- curl 10.32.0.5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

Please notice that a direction from backend -> frontend does not work (as it suppose to be)

root@scw-k8s-cks:~# k exec -it backend -- curl 10.32.0.4
...
# times out ...

One more extended use case with connection to cassandra database

root@scw-k8s-cks:~# k create namespace namespace-cassandra
namespace/namespace-cassandra created

# create a label on pod <- this is not needed but it's good to see how to add label and remove label from a POD
root@scw-k8s-cks:~# k label pod --namespace namespace-cassandra cassandra ns=cassandra
pod/cassandra labeled
root@scw-k8s-cks:~# k label pod --namespace namespace-cassandra cassandra ns-


# create a label on a namespace
root@scw-k8s-cks:~# k label namespace namespace-cassandra ns=cassandra
namespace/namespace-cassandra labeled

# check labels
root@scw-k8s-cks:~# k get ns namespace-cassandra --show-labels
NAME                  STATUS   AGE   LABELS
namespace-cassandra   Active   12m   kubernetes.io/metadata.name=namespace-cassandra,ns=cassandra

root@scw-k8s-cks:~# k expose pod --namespace namespace-cassandra cassandra --port 80
service/cassandra exposed

# Check cassandra IPv4 address
root@scw-k8s-cks:~# k get pods -o wide -n namespace-cassandra
NAME        READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
cassandra   1/1     Running   0          30m   10.32.0.6   scw-k8s-cks   <none>           <none>

Create one more policy
iroot@scw-k8s-cks:~# cat backend-to-cassandra.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-to-cassandra
  namespace: default
spec:
  podSelector:
    matchLabels:
      run: backend
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          ns: cassandra
    ports:
    - protocol: TCP
      port: 80


k create -f backend-to-cassandra.yaml
Check connection from backend to Cassandra
root@scw-k8s-cks:~# k exec backend -- curl http://10.32.0.6
<!DOCTYPE html>
<html>
<head>
...
</body>
</html>
root@scw-k8s-cks:~#
Make it more complex - create default deny in namespace-cassandra to block all traffic
root@scw-k8s-cks:~# cat default-deny-cassandra.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: cassandra-deny-policy
  namespace: namespace-cassandra
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

k create -f default-deny-cassandra.yaml

Now, connection between backend and cassandra does not work anymore.

root@scw-k8s-cks:~# k exec backend -- curl http://10.32.0.6

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0^C
# Create a new label on default namespace
root@scw-k8s-cks:~# k label namespaces default ns=default
namespace/default labeled


# Create a new network policy for Ingress at pod cassandra
root@scw-k8s-cks:~# cat from-backend-to-cassandra.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-to-cassandra
  namespace: namespace-cassandra
spec:
  podSelector:
    matchLabels:
      run: cassandra
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          ns: default

k create -f from-backend-to-cassandra.yaml          
Check the connection now from backend to cassandra
root@scw-k8s-cks:~# k exec backend -- curl http://10.32.0.6
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   615  100   615    0     0   200k      0 --:--:-- --:--:-- --:--:--  200k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Allow DNS 53 from default namespace
cat <<EOF > allow-dns-np.yaml
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  - Ingress
  egress:
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP
EOF
There are existing Pods in Namespace app.

We need a new default-deny NetworkPolicy named deny-out for all outgoing traffic of these Pods. It should still allow DNS traffic on port 53 TCP and UDP.

cat np.yaml 
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-out
  namespace: app
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    ports:
    - protocol: TCP
      port: 53
    - protocol: UDP
      port: 53
author image

Jan Toth

I have been in DevOps related jobs for past 6 years dealing mainly with Kubernetes in AWS and on-premise as well. I spent quite a lot …

comments powered by Disqus