Kubernetes Network Policies
Introduction
This tutorial will guide you through creating and applying Kubernetes Network Policies. Network Policies control traffic flow at the IP address or port level (OSI layer 3 or 4). You will learn how to restrict both ingress (incoming) and egress (outgoing) traffic for your pods, enhancing the security of your Kubernetes cluster.
Prerequisites:
- A running Kubernetes cluster (minikube, kind, or a cloud provider).
kubectlconfigured to connect to your cluster.- Basic understanding of Kubernetes concepts (Pods, Deployments, Services).
Task 1: Setting up the Namespace and Deployments
First, create a dedicated namespace for our demonstration and deploy a few applications. This will allow us to isolate our network policies and deployments.
-
Create a namespace called
network-policy-demo:NODE_TYPE // yamlapiVersion: v1 kind: Namespace metadata: name: network-policy-demoNODE_TYPE // bashkubectl apply -f - <<EOF apiVersion: v1 kind: Namespace metadata: name: network-policy-demo EOFNODE_TYPE // outputnamespace/network-policy-demo created -
Deploy two applications:
webanddb, within thenetwork-policy-demonamespace.web.yaml:
NODE_TYPE // yamlapiVersion: apps/v1 kind: Deployment metadata: name: web namespace: network-policy-demo labels: app: web spec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: web image: nginx:latest ports: - containerPort: 80db.yaml:
NODE_TYPE // yamlapiVersion: apps/v1 kind: Deployment metadata: name: db namespace: network-policy-demo labels: app: db spec: replicas: 1 selector: matchLabels: app: db template: metadata: labels: app: db spec: containers: - name: db image: postgres:14 ports: - containerPort: 5432 env: - name: POSTGRES_PASSWORD value: securepasswordNODE_TYPE // bashkubectl apply -f web.yaml kubectl apply -f db.yamlNODE_TYPE // outputdeployment.apps/web created deployment.apps/db createdCreateweb.yamlanddb.yamlusing your preferred text editor and then apply the deployment configurations. -
Verify the deployments are running:
NODE_TYPE // bashkubectl get deployments -n network-policy-demoNODE_TYPE // outputNAME READY UP-TO-DATE AVAILABLE AGE db 1/1 1 1 <age> web 1/1 1 1 <age>
Task 2: Testing Connectivity Before Network Policies
Before applying any Network Policies, let’s confirm that the web pod can connect to the db pod.
-
Get the name of the
webpod:NODE_TYPE // bashkubectl get pods -n network-policy-demo -l app=web -o nameNODE_TYPE // outputpod/web-<random-string> -
Exec into the
webpod and installtelnet:NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- apt-get update && apt-get install -y telnetReplace<web-pod-name>with the actual name of the web pod. You may need to adjust the package manager based on the container image. For example, some images may useapk add telnet. -
Get the name of the
dbpod:NODE_TYPE // bashkubectl get pods -n network-policy-demo -l app=db -o nameNODE_TYPE // outputpod/db-<random-string> -
Test connectivity from the
webpod to thedbpod on port 5432:NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- telnet <db-pod-name> 5432NODE_TYPE // outputTrying <db-pod-ip>... Connected to <db-pod-name>. Escape character is '^]'.If the command connects (shows “Connected to …”), it confirms connectivity before any policies are in place. Type
Ctrl+]thenqto exittelnet.
Task 3: Implementing a Default Deny Network Policy
As a best practice, start by implementing a default deny policy for the entire namespace. This blocks all ingress and egress traffic unless explicitly allowed.
-
Create a Network Policy called
default-denyin thenetwork-policy-demonamespace:NODE_TYPE // yamlapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: network-policy-demo spec: podSelector: {} policyTypes: - Ingress - EgressNODE_TYPE // bashkubectl apply -f - <<EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: network-policy-demo spec: podSelector: {} policyTypes: - Ingress - Egress EOFNODE_TYPE // outputnetworkpolicy.networking.k8s.io/default-deny createdpodSelector: {}selects all pods in the namespace.policyTypes: - Ingress - Egressapplies the default deny to both incoming and outgoing traffic. -
Re-run the connectivity test from the
webpod to thedbpod. It should now fail.NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- telnet <db-pod-name> 5432The connection will likely time out, indicating that the network policy is blocking the traffic.
Task 4: Allowing Ingress Traffic to the db pod
Now, create a Network Policy to allow only traffic from the web pod to the db pod on port 5432.
-
Create a Network Policy called
allow-web-to-dbin thenetwork-policy-demonamespace:NODE_TYPE // yamlapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-web-to-db namespace: network-policy-demo spec: podSelector: matchLabels: app: db policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: web ports: - protocol: TCP port: 5432NODE_TYPE // bashkubectl apply -f - <<EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-web-to-db namespace: network-policy-demo spec: podSelector: matchLabels: app: db policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: web ports: - protocol: TCP port: 5432 EOFNODE_TYPE // outputnetworkpolicy.networking.k8s.io/allow-web-to-db createdThis policy selects pods with the labelapp: dband allows ingress traffic from pods with the labelapp: webon TCP port 5432. -
Re-run the connectivity test from the
webpod to thedbpod. It should now succeed.NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- telnet <db-pod-name> 5432The connection should now be established.
Task 5: Allowing Egress Traffic from the web pod to the Internet (Example)
In many real-world scenarios, you need to allow egress traffic from your pods to external services. This example demonstrates allowing the web pod to make DNS queries.
-
Create a Network Policy called
allow-web-dns-egressin thenetwork-policy-demonamespace:NODE_TYPE // yamlapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-web-dns-egress namespace: network-policy-demo spec: podSelector: matchLabels: app: web policyTypes: - Egress egress: - to: - namespaceSelector: {} # all namespaces podSelector: {} # all pods ports: - protocol: UDP port: 53NODE_TYPE // bashkubectl apply -f - <<EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-web-dns-egress namespace: network-policy-demo spec: podSelector: matchLabels: app: web policyTypes: - Egress egress: - to: - namespaceSelector: {} # all namespaces podSelector: {} # all pods ports: - protocol: UDP port: 53 EOFNODE_TYPE // outputnetworkpolicy.networking.k8s.io/allow-web-dns-egress createdThis policy selects pods with the labelapp: weband allows egress traffic to any pod on UDP port 53 (DNS). In a real-world scenario, you should limit thetosection to your cluster’s DNS service IP range. -
Exec into the
webpod and test DNS resolution. You can usenslookupordig. First you must installdnsutils:NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- apt-get update && apt-get install -y dnsutilsThen, test DNS resolution of a public domain:
NODE_TYPE // bashkubectl exec -n network-policy-demo -it <web-pod-name> -- nslookup google.comIf DNS resolution works, the egress policy is correctly configured.
Conclusion
In this tutorial, you learned how to:
- Create a Kubernetes namespace and deploy applications.
- Implement a default deny Network Policy.
- Allow specific ingress traffic between pods.
- Allow egress traffic from a pod to the internet (specifically DNS).
By understanding and implementing Network Policies, you can significantly enhance the security and isolation of your Kubernetes workloads. Remember to always start with a default deny policy and carefully define the necessary ingress and egress rules for each application.