Network Policies advanced concepts
Note:
The ingress network policy was not working until having cilium deployed.
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
The following manifest specifies a network policy controlling the egress traffic from Pods labelled "app=foo" with two allowed destinations:
-
Pods in the same namespace labelled "app=hello".
-
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
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
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 )
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.