Kubernetes - Ingress Policy

 



Kubernetes provides a resource called NetworkPolicy that allows rules to allow/deny network traffic, which works like a network firewall.By default using this resource doesn't do anything. To make it work, you need first to add a Kubernetes Networking plugin that implements it.Some Kubernetes cluster providers propose their implementation, like GKS and AKS. On the other side, you can use Calico, like recommended by AWS with EKS.

I have installed calico network policy agent for the network policy to work.

curl https://projectcalico.docs.tigera.io/v3.23/manifests/calico-policy-only.yaml -o calico.yaml

kubectl apply -f calico.yaml

Lets create a namespace "production".

root@master:~# kubectl create ns production

namespace/production created

root@master:~#

Creating a nginx pod under "production" namespace.

root@master:~# kubectl run nginx -n production --image nginx --labels app=nginx --expose --port 80

service/nginx created

pod/nginx created

root@master:~#

root@master:~# kubectl get all -n production

NAME        READY   STATUS    RESTARTS   AGE

pod/nginx   1/1     Running   0          37s

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE

service/nginx   ClusterIP   10.98.247.195   <none>        80/TCP    37s

root@master:~#

Now try to access this Nginx pod from another pod. Use this command for the verification.

root@master:~# kubectl get pods -A -n production -o wide  | grep -i nginx

production    nginx                                      1/1     Running   0             2m43s   10.244.0.7        master   <none>           <none>

root@master:~#


Accessing pod IP from host machine:

root@master:~# curl 10.244.0.7

<!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>

root@master:~#

Lets try to access from a pod on another namespace.

root@master:~# kubectl run test-pod --image nginx

pod/test-pod created

root@master:~#

root@master:~# kubectl get pods -o wide

NAME       READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES

test-pod   1/1     Running   0          19s   10.244.0.10   master   <none>           <none>

root@master:~# 

root@master:~# kubectl exec -it test-pod -- curl 10.244.0.7

<!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>

root@master:~#


Deny All Traffic to Pod:

You should be able to access the Nginx pod without any issue. It is the default and expected behavior, and there is nothing new about this setup.

Let’s try to change this default behavior by introducing a network policy that should deny all incoming traffic by default for pods in the "production" namespace.

root@master:/kube# cat network_policy.yml

kind: NetworkPolicy

apiVersion: networking.k8s.io/v1

metadata:

  name: deny-all-policy

  namespace: production # Namespace

spec:

  podSelector:

    matchLabels:

      app: nginx # App label

  ingress: []

root@master:/kube#



We implement this network policy in "production" namespace.

root@master:/kube# kubectl apply -f  network_policy.yml

networkpolicy.networking.k8s.io/deny-all-policy created

root@master:/kube#

root@master:/kube# kubectl get networkpolicy -n production

NAME              POD-SELECTOR   AGE

deny-all-policy   app=nginx      15s

root@master:/kube#

root@master:/kube# kubectl describe networkpolicy -n production

Name:         deny-all-policy

Namespace:    production

Created on:   2022-07-20 09:15:47 -0700 MST

Labels:       <none>

Annotations:  <none>

Spec:

  PodSelector:     app=nginx

  Allowing ingress traffic:

    <none> (Selected pods are isolated for ingress connectivity)

  Not affecting egress traffic

  Policy Types: Ingress

root@master:/kube#


Lets test it out.

root@master:/kube# kubectl exec -it test-pod -- curl 10.244.0.7

curl: (28) Failed to connect to 10.244.0.7 port 80: Connection timed out

command terminated with exit code 28

root@master:/kube#


Lets test connection by creating a pod under "production" namespace with the label “app=nginx”.

root@master:/kube# kubectl run test --image=nginx -l app=nginx -n production

pod/test created

root@master:/kube# kubectl get pod -n production --show-labels -o wide

NAME    READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

nginx   1/1     Running   0          83m   10.244.0.7    master   <none>           <none>            app=nginx

test    1/1     Running   0          17s   10.244.0.17   master   <none>           <none>            app=nginx

root@master:/kube#


root@master:/kube# kubectl exec -it test -n production sh -- curl 10.244.0.7

^Ccommand terminated with exit code 130

root@master:/kube#


DENY ALL - Going to deny all the incoming traffic.


Allow/limit Traffic to Pod:

In this section, you will allow traffic from only those pods with the matching label as app=nginx. To test this, use the following network policy.

root@master:/kube# cat network_policy.yml

kind: NetworkPolicy

apiVersion: networking.k8s.io/v1

metadata:

  name: allow-policy

  namespace: production

spec:

  podSelector:

    matchLabels:

      app: nginx

  ingress:

  - from:

      - podSelector:

          matchLabels:

            app: nginx

root@master:/kube#


root@master:/kube# kubectl get networkpolicy -A

NAMESPACE    NAME           POD-SELECTOR   AGE

production   allow-policy   app=nginx      2s

root@master:/kube#


root@master:/kube# kubectl get pods -n production -o wide --show-labels

NAME    READY   STATUS    RESTARTS      AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

nginx   1/1     Running   0             62m   10.244.0.7    master   <none>           <none>            app=nginx

test    1/1     Running   1 (26s ago)   41s   10.244.0.13   master   <none>           <none>            app=nginx

root@master:/kube#


root@master:/kube# kubectl get pods -n production -o wide --show-labels

NAME    READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

nginx   1/1     Running   0          89m     10.244.0.7    master   <none>           <none>            app=nginx

test    1/1     Running   0          6m34s   10.244.0.17   master   <none>           <none>            app=nginx


root@master:/kube# kubectl exec -it test -n production sh -- curl 10.244.0.7

<!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>

root@master:/kube#


Now I can access the pod from “production” namespace with the label “app=nginx". Lets create another pod under "production" namespace with different label "app=java".

root@master:/kube# kubectl get pods -n production -o wide --show-labels

NAME    READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

java    1/1     Running   0          8s      10.244.0.18   master   <none>           <none>            app=java

nginx   1/1     Running   0          91m     10.244.0.7    master   <none>           <none>            app=nginx

test    1/1     Running   0          8m37s   10.244.0.17   master   <none>           <none>            app=nginx

root@master:/kube#


Lets test:


root@master:/kube# kubectl exec -it java -n production  sh -- curl 10.244.0.17

^Ccommand terminated with exit code 130

root@master:/kube#


Not accessbile.

Now, Lets test by creating a pod under "default" namespace with the label “app=nginx".

root@master:/kube# kubectl run test --image=nginx -l app=nginx

pod/test created

root@master:/kube# kubectl get pods -o wide --show-labels

NAME   READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

test   1/1     Running   0          10s   10.244.0.19   master   <none>           <none>            app=nginx

root@master:/kube#


root@master:/kube# kubectl exec -it test sh -- curl 10.244.0.7

^Ccommand terminated with exit code 130

root@master:/kube#

Not accessible. This policy is deployed to production namespace, so pods from other namespaces are not allowed.


Allow/limit Traffic to Pod from "dev" namespace:


Creating a "dev" namespace.

root@master:/kube# kubectl create ns dev

namespace/dev created

root@master:/kube#


Label the namespace as "env=dev".


root@master:/kube# kubectl describe ns dev

Name:         dev

Labels:       env=dev

              kubernetes.io/metadata.name=dev

Annotations:  <none>

Status:       Active


No resource quota.


No LimitRange resource.

root@master:/kube#


root@master:/kube# cat ns_allow.yml

kind: NetworkPolicy

apiVersion: networking.k8s.io/v1

metadata:

  name: allow-different-namespace-policy

  namespace: production

spec:

  podSelector:

    matchLabels:

      app: nginx

  ingress:

  - from:

    - podSelector:

        matchLabels:

          app: nginx

      namespaceSelector:

        matchLabels:

          env: dev

root@master:/kube#


root@master:/kube# kubectl get networkpolicy -n production

NAME                               POD-SELECTOR   AGE

allow-different-namespace-policy   app=nginx      18s

root@master:/kube#


root@master:/kube# kubectl describe networkpolicy allow-different-namespace-policy -n production

Name:         allow-different-namespace-policy

Namespace:    production

Created on:   2022-07-20 10:52:30 -0700 MST

Labels:       <none>

Annotations:  <none>

Spec:

  PodSelector:     app=nginx

  Allowing ingress traffic:

    To Port: <any> (traffic allowed to all ports)

    From:

      NamespaceSelector: env=dev

      PodSelector: app=nginx

  Not affecting egress traffic

  Policy Types: Ingress

root@master:/kube#


Lets create a test pod under "dev" namespace with label "app=nginx".


root@master:/kube# kubectl run test --image nginx -l app=nginx -n dev

pod/test created

root@master:/kube#


root@master:/kube# kubectl get pods -n dev -o wide --show-labels

NAME   READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS

test   1/1     Running   0          19s   10.244.0.20   master   <none>           <none>            app=nginx

root@master:/kube#


root@master:/kube# kubectl exec -it test -n dev sh -- curl 10.244.0.7

<!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>

root@master:/kube#


It works.


Comments

Popular posts from this blog

SRE/DevOps Syllabus

AWS Code Commit - CI/CD Series Part 1

Docker - Preventing IP overlapping