Skip to main content

Network Security Policies

For this session, we can review the CKA material. I'll only include the content differences.

  • They are the firewall rules in Kubernetes.
  • Implemented by the CNI, not all Network Plugins support them.
  • Namespace level.
  • Restricts ingress and egress for a group of pods based on certain conditions.
  • Network Policies.

In this first scenario, we are applying an egress rule where we deny everything unless it passes a rule. Since we don't have rules, everything is denied.

alt text

Here we already have egress rules.

alt text

We can create multiple network policies for the same pods. Practically a merge.

  • If a pod has more than one NP
    • Then we'll have the union of all NPs applied to it.
    • Order doesn't matter, the result is always the same.

Knowing this, we can create an NP to deny everything in each namespace and only allow what is necessary.

Let's run two pods in the default namespace and check if they can see each other.

root@cks-master:~# kubectl get pods
No resources found in default namespace.

root@cks-master:~# k run frontend --image=nginx
pod/frontend created

root@cks-master:~# k run backend --image=nginx
pod/backend created

root@cks-master:~# k expose pod frontend --port 80
service/frontend exposed

root@cks-master:~# k expose pod backend --port 80
service/backend exposed

root@cks-master:~# k get pod,svc
NAME READY STATUS RESTARTS AGE
pod/backend 1/1 Running 0 46s
pod/frontend 1/1 Running 0 59s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/backend ClusterIP 10.111.182.74 <none> 80/TCP 20s
service/frontend ClusterIP 10.104.14.250 <none> 80/TCP 27s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 44h

# Executing a curl inside frontend to backend

root@cks-master:~# k exec frontend -- curl backend
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 73652 0 <!DOCTYPE html>-- --:--:-- 0
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
--:--:-- --:--:-- --:--:-- 76875

root@cks-master:~# k exec backend -- curl frontend
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 221k 0 --:--:-- --:--:-- --:--:-- 300k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

We can observe that communication exists. Let's create a default NP and only allow what is necessary.

Create a file and apply it to the cluster.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
root@cks-master:~# mkdir default
root@cks-master:~# cd default/
root@cks-master:~/default# vi np-default-deny.yaml
root@cks-master:~/default# kubectl apply -f np-default-deny.yaml
networkpolicy.networking.k8s.io/default-deny created

root@cks-master:~/default# k get networkpolicies
NAME POD-SELECTOR AGE
default-deny <none> 48s
root@cks-master:~/default# k describe networkpolicies default-deny
Name: default-deny
Namespace: default
Created on: 2024-08-17 17:33:21 +0000 UTC
Labels: <none>
Annotations: <none>
Spec:
PodSelector: <none> (Allowing the specific traffic to all pods in this namespace)
Allowing ingress traffic:
<none> (Selected pods are isolated for ingress connectivity)
Allowing egress traffic:
<none> (Selected pods are isolated for egress connectivity)
Policy Types: Ingress, Egress

# If we try communication again we see that we can no longer get the nginx page.

root@cks-master:~/default# k exec frontend -- curl backend
% 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:14 --:--:--
root@cks-master:~/default#

Let's allow the frontend pod to exit to the backend.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend
namespace: default
spec:
podSelector:
matchLabels:
run: frontend # When running the run command we have this standardized label
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
run: backend

Let's create and apply this policy.

root@cks-master:~/default# vim np-frontend.yaml
root@cks-master:~/default# kubectl apply -f np-frontend.yaml
networkpolicy.networking.k8s.io/frontend created
root@cks-master:~/default# k exec frontend -- curl backend
% 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

We still can't connect because the backend pod is denying everything, so let's allow its entry.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend
namespace: default
spec:
podSelector:
matchLabels:
run: backend # When running the run command we have this standardized label
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
run: frontend

Let's allow entry for frontend pods in the backend and test.

root@cks-master:~/default# vim np-backend.yaml

root@cks-master:~/default# kubectl apply -f np-backend.yaml
networkpolicy.networking.k8s.io/backend created

# We still can't
root@cks-master:~/default# k exec frontend -- curl backend
% 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:02 --:--:--

root@cks-master:~/default# k get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
backend 1/1 Running 0 26m 192.168.1.3 cks-worker <none> <none>
frontend 1/1 Running 0 26m 192.168.1.2 cks-worker <none> <none>

# Trying directly by IP we can
root@cks-master:~/default# k exec frontend -- curl 192.168.1.3
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
100 615 100 615 0 0 399k 0 --:--:-- --:--:-- --:--:-- 600k

What's happening is that we can't resolve names because we don't have access to core-dns. We need to enable this on all pods in the namespace. To make this easy, we can apply this rule to all pods at once. We can change our default-deny or create another NP. Let's extend the default-deny and only allow egress to port 53.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
egress:
- to:
ports:
- port: 53
protocol: TCP
- port : 53
protocol: UDP
root@cks-master:~/default# vim np-default-deny.yaml

root@cks-master:~/default# k apply -f np-default-deny.yaml
networkpolicy.networking.k8s.io/default-deny configured

# Working
root@cks-master:~/default# k exec frontend -- curl backend
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 268k 0 --:--:-- --:--:-- --:--:-- 300k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# And just to note, we don't allow backend to communicate with frontend
# We also don't allow entries in frontend. We only allow one direction frontend > backend.

root@cks-master:~/default# k exec backend -- curl frontend
% 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:02 --:--:-- 0^C
root@cks-master:~/default# k exec backend -- curl 192.168.1.2
% 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
root@cks-master:~/default#