Skip to content

Network Policies advanced concepts

Ramkumar edited this page Jun 26, 2022 · 16 revisions

Note:

The ingress network policy was not working until having cilium deployed.

Test: Restrict ingress - The Pod accepts Traffic only from Pods labelled "app=foo"

First, run a web server application with label app=hello and expose it internally in the cluster:

kubectl run hello-web --labels app=hello \
  --image=gcr.io/google-samples/hello-app:1.0 --port 8080 --expose

Next, configure a NetworkPolicy to allow traffic to the hello-web Pods from only the app=foo Pods. Other incoming traffic from Pods that do not have this label, external traffic, and traffic from Pods in other namespaces are blocked.

The following manifest selects Pods with label app=hello and specifies an Ingress policy to allow traffic only from Pods with the label app=foo:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: hello-allow-from-foo
spec:
  policyTypes:
  - Ingress
  podSelector:
    matchLabels:
      app: hello
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: foo
  • To apply this policy to the cluster, run the following command:

kubectl apply -f hello-allow-from-foo.yaml

  • Validate the Ingress policy First, run a temporary Pod with the label app=foo and get a shell in the Pod:

kubectl run -l app=foo --image=alpine --restart=Never --rm -i -t test-1

  • Make a request to the hello-web:8080 endpoint to verify that the incoming traffic is allowed:

wget -qO- --timeout=2 http://hello-web:8080

Traffic from Pod app=foo to the app=hello Pods is enabled.

Next, run a temporary Pod with a different label (app=other) and get a shell inside the Pod:

kubectl run -l app=other --image=alpine --restart=Never --rm -i -t test-1

Make the same request to observe that the traffic is not allowed and therefore the request times out, then exit from the Pod shell:

wget -qO- --timeout=2 http://hello-web:8080

Test: Restricting outgoing traffic from the Pods

The following manifest specifies a network policy controlling the egress traffic from Pods labelled "app=foo" with two allowed destinations:

  1. Pods in the same namespace labelled "app=hello".

  2. Cluster Pods or external endpoints on port 53 (UDP and TCP).

Note: The Calico networking solutions (used in this testing) does NOT support the Port Level restrictions imposed in the example.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: foo-allow-to-hello
spec:
  policyTypes:
  - Egress
  podSelector:
    matchLabels:
      app: foo
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: hello
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP

To apply this policy to the cluster, run the following command:

kubectl apply -f foo-allow-to-hello.yaml

Validate the egress policy

First, deploy a new web application called hello-web-2 and expose it internally in the cluster:

kubectl run hello-web --labels app=hello \
  --image=gcr.io/google-samples/hello-app:1.0 --port 8080 --expose 

kubectl run hello-web2 --labels app=hello-web2 \
  --image=gcr.io/google-samples/hello-app:1.0 --port 8080 --expose 

Next, run a temporary Pod labelled app=foo and open a shell inside the container:

kubectl run -l app=foo --image=alpine --rm -i -t --restart=Never test-3

Validate that the Pod can establish connections to hello-web:8080:

wget -qO- --timeout=2 http://hello-web:8080

Validate that the Pod cannot establish connections to hello-web-2:8080:

wget -qO- --timeout=2 http://hello-web-2:8080

Test: ALLOW traffic from some pods in another namespace

Since Kubernetes v1.11, it is possible to combine podSelector and namespaceSelector with an AND (intersection) operation.

warning:- This feature is available on Kubernetes v1.11 or after. Most networking plugins do not yet support this feature. Make sure to test this policy after you deploy it to make sure it is working correctly.

** Example: **

Start a web application:

kubectl run  web --image=nginx --labels=app=web --expose --port 80

** Create a namespace named "other" labelled "team=operation" **

kubectl create namespace other
kubectl label namespace/other team=operations

The following manifest allows traffic only from pods with label "type=monitoring" located in a namespace labelled "team=operations".

web-allow-all-ns-monitoring.yaml:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all-ns-monitoring
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
      - namespaceSelector:     # chooses all pods in namespaces labelled with team=operations
          matchLabels:
            team: operations  
        podSelector:           # chooses pods with type=monitoring
          matchLabels:
            type: monitoring
$ kubectl apply -f web-allow-all-ns-monitoring.yaml

networkpolicy.networking.k8s.io/web-allow-all-ns-monitoring created

Try it out

Query this web server from default namespace, without labelling the application type=monitoring, observe it is blocked:

$ kubectl run test-$RANDOM --rm -i -t --image=alpine -- sh

If you don't see a command prompt, try pressing enter.

/ # wget -qO- --timeout=2 http://web.default
wget: download timed out

(traffic blocked)

Query this web server from default namespace, labelling the application type=monitoring, observe it is blocked:

kubectl run --generator=run-pod/v1 test-$RANDOM --labels type=monitoring --rm -i -t --image=alpine -- sh

If you don't see a command prompt, try pressing enter. / # wget -qO- --timeout=2 http://web.default wget: download timed out

(traffic blocked)

Query this web server from other namespace, without labelling the pod with "type=monitoring", observe it is blocked:

$ kubectl run --generator=run-pod/v1 test-$RANDOM --namespace=other --rm -i -t --image=alpine -- sh

If you don't see a command prompt, try pressing enter. / # wget -qO- --timeout=2 http://web.default wget: download timed out

(traffic blocked) Query this web server from other namespace, labelling the pod "type=monitoring", observe it is allowed:

kubectl run test-$RANDOM --namespace=other --labels type=monitoring --rm -i -t --image=alpine -- sh

If you don't see a command prompt, try pressing enter. / # wget -qO- --timeout=2 http://web.default

... (traffic allowed)

Cleanup

kubectl delete networkpolicy web-allow-all-ns-monitoring
kubectl delete namespace other
kubectl delete pod web
kubectl delete service web

ALLOW traffic from some pods or from another namespace

change network policy as below

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all-ns-monitoring
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
      - namespaceSelector:     # chooses all pods in namespaces labelled with team=operations
          matchLabels:
            team: operations  
      - podSelector:           # chooses pods with type=monitoring
          matchLabels:
            type: monitoring

Now the above pod(s) labelled "web" is/are accessible to those pods labelled as "monitoring" or running in the namespace labelled "operations" ( basically its an "or" operation )

Example ingress/egress restricted by nameseletors/podselectors/ports/IP blocks

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
    - protocol: TCP
      port: 80

  egress:
  - to:
    - ipBlock:
        cidr: 10.0.1.0/24
    ports:
    - protocol: TCP
      port: 80

Checking egress configuration:

Start 2 pods named web & dest-nginx with a service @port#80:

kubectl run  web --image=nginx --labels=role=db --expose --port=80
kubectl run  test-ram  --labels=role=frontend --rm -i -t --image=alpine -- sh

connecting to the pod test-ram and executing the below. It works.

wget http://web.default

Example checking egress with podSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
    - protocol: TCP
      port: 80

  egress:
  - to:
    - podSelector:
        matchLabels:
          role: frontend

Start 2 pods to validate the egress podselector is working:

kubectl run  web --image=nginx --labels=role=db --expose --port=80
kubectl run  dest-nginx --image=nginx --labels=role=frontend --expose --port 80

Connecting to the pod and executing curl command works fine:

kubectl exec -it web -- /bin/bash
curl http://web

Note:

The egress part with IPBlock was not working for some reasons. It needs to be checked later.

Clone this wiki locally