Network Policies in Kubernetes
Network Policies in Kubernetes are used to control the flow of network traffic at the IP address or port level within a cluster. These policies are crucial when you need to define rules for traffic flow between pods, or between pods and external entities, based on protocols like TCP, UDP, and SCTP.
Key Concepts:
- Application-Centric: Network Policies are designed around applications, meaning you specify how a pod can communicate with other network entities, which can include other pods, namespaces, or IP blocks.
- Selectors:
- Pod Selector: Defines which pods the policy applies to.
- Namespace Selector: Determines which namespaces the pods are allowed to communicate with.
- IP Block: Defines IP address ranges that are allowed or denied traffic.
2. Types of Isolation:
- Ingress Isolation: Controls inbound traffic to the pod. A pod is isolated for ingress if any NetworkPolicy with “Ingress” in its
policyTypes
applies to it. - Egress Isolation: Controls outbound traffic from the pod. A pod is isolated for egress if any NetworkPolicy with “Egress” in its
policyTypes
applies to it.
3. Policy Types:
- Ingress: Specifies the incoming connections that are allowed to the pod.
- Egress: Specifies the outgoing connections that are allowed from the pod.
4. Additive Effect: Network policies do not conflict with each other; their effects combine. If multiple policies apply to a pod, the allowed connections are the union of what each policy permits.
Example:
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
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
- This example defines a policy for a pod labeled with
role: db
:
- Ingress: Allows traffic from a specified IP block (excluding a sub-range), a namespace labeled
project: myproject
, and pods labeledrole: frontend
. - Egress: Allows outbound traffic to a specific IP block on TCP port 5978.
Prerequisites:
- The Kubernetes cluster must use a network plugin that supports NetworkPolicy enforcement, otherwise, creating a NetworkPolicy will have no effect.
By implementing Network Policies, you can fine-tune the security and accessibility of your applications within a Kubernetes cluster, ensuring that only the desired traffic is allowed, and unwanted traffic is restricted.
When configuring NetworkPolicies in Kubernetes, there are certain mandatory fields and considerations that you need to keep in mind to ensure proper functionality and enforcement. Here’s a breakdown:
Mandatory Fields:
- apiVersion: Specifies the API version of the Kubernetes resource. For NetworkPolicies, it is typically
networking.k8s.io/v1
. - kind: Specifies the type of Kubernetes resource. For NetworkPolicies, this is
NetworkPolicy
. - metadata: Contains metadata about the NetworkPolicy, such as
name
andnamespace
. This is required for identifying and organizing the policy within the cluster. - spec: The
spec
field contains all the information needed to define a NetworkPolicy. This includes the specific rules and selectors that control traffic flow.
Key Components within spec
:
- podSelector: Defines which pods the policy applies to within the namespace. For example,
podSelector: matchLabels: role: db
will apply the policy to pods labeledrole=db
. An emptypodSelector
applies the policy to all pods in the namespace. - policyTypes: Specifies whether the policy applies to ingress traffic, egress traffic, or both. If not explicitly defined,
Ingress
is set by default, andEgress
is set if any egress rules are specified. - ingress: A list of rules that define allowed ingress traffic. Each rule matches traffic based on the
from
andports
fields. For example, the policy might allow traffic from a specific IP block, namespace, or pods with certain labels on a specific port. - egress: A list of rules that define allowed egress traffic. Similar to
ingress
, it matches traffic based on theto
andports
fields. For example, it might allow traffic to a certain CIDR range on a specific port.
Example NetworkPolicy Behavior:
- Isolation: The example policy isolates pods with
role=db
in thedefault
namespace for both ingress and egress traffic. - Ingress Rules:
- Allows traffic on TCP port 6379 from:
- Pods with
role=frontend
in thedefault
namespace. - Pods in namespaces labeled
project=myproject
. - IP addresses in the range
172.17.0.0/16
, excluding172.17.1.0/24
.
3. Egress Rules:
- Allows traffic from
role=db
pods to the10.0.0.0/24
CIDR on TCP port 5978.
Selectors in Ingress and Egress Rules:
- podSelector: Selects specific pods within the same namespace as the NetworkPolicy to allow as ingress sources or egress destinations.
- namespaceSelector: Selects specific namespaces where all pods are allowed as ingress sources or egress destinations.
- namespaceSelector + podSelector: Combines both to select specific pods within specific namespaces. Be careful with YAML syntax as it determines whether you’re combining selectors or creating separate rules.
- ipBlock: Selects particular IP CIDR ranges as ingress sources or egress destinations. Typically used for cluster-external IPs.
Special Considerations:
- Source IP Rewriting: The actual source IP that the NetworkPolicy acts on may vary depending on how ingress and egress mechanisms are implemented. This can depend on factors such as network plugins, cloud providers, and service implementations. This means that in some cases, filtering might occur based on the original source IP, while in other cases, the policy might act on the IP of a LoadBalancer, node, or another intermediate entity.
By default, Kubernetes allows all ingress and egress traffic to and from pods within a namespace if no NetworkPolicies are defined. However, you can modify this default behavior to enforce stricter controls using specific NetworkPolicies. Here’s how you can configure default policies to either deny or allow traffic:
1. Default Deny All Ingress Traffic
To deny all incoming traffic by default for a namespace, you can create a NetworkPolicy that selects all pods and does not allow any ingress traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
- Effect: All pods in the namespace are isolated from any ingress traffic unless another NetworkPolicy explicitly allows it.
- Scope: This policy does not affect egress traffic.
2. Allow All Ingress Traffic
If you want to explicitly allow all incoming connections to all pods in a namespace, you can create a policy that permits any ingress traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
- Effect: All pods in the namespace are open to any incoming connections. No other NetworkPolicy can override this to deny ingress traffic.
- Scope: This policy does not affect egress traffic.
3. Default Deny All Egress Traffic
To deny all outgoing traffic by default, you can create a NetworkPolicy that applies to all pods and does not allow any egress traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
- Effect: All pods in the namespace are isolated from any egress traffic unless explicitly allowed by another NetworkPolicy.
- Scope: This policy does not affect ingress traffic.
4. Allow All Egress Traffic
To allow all outgoing connections from all pods in a namespace, you can create a policy that explicitly permits any egress traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
- Effect: All pods in the namespace can freely communicate with external entities. No other NetworkPolicy can override this to deny egress traffic.
- Scope: This policy does not affect ingress traffic.
5. Default Deny All Ingress and Egress Traffic
To block both ingress and egress traffic by default for all pods in a namespace, you can create a comprehensive deny-all NetworkPolicy.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
- Effect: All pods in the namespace are fully isolated, blocking both incoming and outgoing traffic unless explicitly allowed by another NetworkPolicy.
Network Traffic Filtering in Kubernetes
Kubernetes allows you to control the flow of network traffic to and from pods using NetworkPolicies. These policies operate at the network layer and primarily focus on Layer 4 connections (TCP, UDP, and optionally SCTP). Here’s a detailed look at how NetworkPolicies work and some specific scenarios:
1. Protocol Support
- Supported Protocols: NetworkPolicies reliably manage TCP, UDP, and optionally SCTP traffic.
- Unsupported Protocols: The behavior for other protocols, such as ARP or ICMP, is undefined. This means that even with strict NetworkPolicies, some protocols might still pass through depending on the underlying CNI (Container Network Interface) plugin.
Note: If you need SCTP support in your NetworkPolicies, ensure your CNI plugin supports this protocol.
2. Deny-All Network Policies
- A “deny all” NetworkPolicy ensures that no TCP, UDP, or SCTP connections are allowed unless explicitly permitted by other policies.
- Important: While such a policy will block the supported protocols, it might not affect other protocols like ICMP, leading to inconsistent behavior across different network plugins.
3. Targeting a Range of Ports
- Feature State: Kubernetes v1.25 [Stable]
- You can specify a range of ports in a NetworkPolicy using the
endPort
field. This is useful when you need to allow or deny traffic across multiple ports.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
- Restrictions:
- The
endPort
must be greater than or equal to theport
. - Both
port
andendPort
must be numeric. - Your CNI plugin must support the
endPort
field; otherwise, the policy will only apply to the singleport
specified.
4. Targeting Multiple Namespaces by Label
- You can use the
namespaceSelector
to target multiple namespaces based on their labels.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-namespaces
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchExpressions:
- key: namespace
operator: In
values: ["frontend", "backend"]
- Note: You cannot directly specify namespace names in a NetworkPolicy; you must use labels to select them.
5. Targeting a Namespace by its Name
- Kubernetes automatically assigns the label
kubernetes.io/metadata.name
to all namespaces, with the value being the namespace's name. You can use this label to target a specific namespace.
6. Pod Lifecycle and NetworkPolicy Application
- Policy Application Timing: When a NetworkPolicy is created, there might be a delay before the CNI plugin fully applies it. Pods started during this delay might not be fully protected.
- Resilience: Pods should be designed to handle scenarios where network connectivity changes after startup. You can use an init container to ensure that critical connections are established before the main application starts.
7. NetworkPolicy and hostNetwork
Pods
- Behavior for
hostNetwork
Pods: - The handling of
hostNetwork
pods by NetworkPolicies is undefined. - Network plugins may either apply NetworkPolicies to
hostNetwork
pods or ignore them, treating traffic from these pods as node traffic.
8. Limitations of NetworkPolicies
- What You Can’t Do:
- Force internal cluster traffic through a common gateway.
- Apply policies related to TLS.
- Create node-specific policies by Kubernetes identity.
- Target services by name.
- Apply default policies to all namespaces or pods.
- Implement advanced policy querying or reachability tooling.
- Log network security events (like blocked or accepted connections).
- Explicitly deny policies (only allow rules can be created).
- Block localhost access or incoming host traffic.
9. Impact on Existing Connections
- Changing Policies: Modifying a NetworkPolicy or the labels of affected pods/namespaces might impact existing connections. Whether a connection is immediately affected depends on the network plugin’s implementation. Therefore, it’s advisable to avoid changes that might disrupt ongoing connections.
These details illustrate the versatility and limitations of Kubernetes NetworkPolicies, helping you design secure, robust networking configurations in your clusters.
Getting Started with Kubernetes NetworkPolicy
The Kubernetes NetworkPolicy API allows you to control how pods communicate with each other within a cluster. This guide will walk you through setting up a basic network policy using an nginx
deployment.
Prerequisites
- Kubernetes Cluster: Ensure you have a Kubernetes cluster with at least two nodes that are not acting as control plane hosts.
- kubectl: The command-line tool should be configured to communicate with your cluster.
- Network Provider: Make sure your Kubernetes cluster is using a network provider that supports NetworkPolicy, such as Antrea, Calico, Cilium, Kube-router, Romana, or Weave Net.
Step 1: Check Kubernetes Version
Make sure your Kubernetes server is at version v1.8 or later:
kubectl version
Step 2: Create an nginx Deployment and Service
First, create an nginx
deployment:
kubectl create deployment nginx --image=nginx
Next, expose the nginx
deployment through a service:
kubectl expose deployment nginx --port=80
Verify that the deployment and service are running:
kubectl get svc,pod
Expected output:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes 10.100.0.1 <none> 443/TCP 46m
service/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
pod/nginx-xxxxxx-yyyyy 1/1 Running 0 35s
Step 3: Test the Service from Another Pod
To test access to the nginx
service from another pod, run a busybox
container:
kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh
In the busybox
shell, try accessing the nginx
service:
wget --spider --timeout=1 nginx
Expected output:
Connecting to nginx (10.100.0.16:80)
remote file exists
Step 4: Limit Access to the nginx Service
Create a NetworkPolicy
to restrict access to the nginx
service. Only pods with the label access: true
should be able to access the service.
Create a file nginx-policy.yaml
with the following content:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
Apply the policy:
kubectl apply -f nginx-policy.yaml
This policy ensures that only pods with the label access=true
can communicate with the nginx
pod.
Step 5: Test Access with the Network Policy in Place
Try accessing the nginx
service from a pod without the correct labels:
kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh
In the shell, run:
wget --spider --timeout=1 nginx
Expected output:
wget: download timed out
Step 6: Define Access Label and Test Again
Now, create a pod with the correct label to test access:
kubectl run busybox --rm -ti --labels="access=true" --image=busybox:1.28 -- /bin/sh
In the shell, run:
wget --spider --timeout=1 nginx
Expected output:
Connecting to nginx (10.100.0.16:80)
remote file exists
This shows that the network policy is effectively controlling access to the nginx
service based on pod labels.
Conclusion
With these steps, you’ve successfully set up and tested a basic NetworkPolicy in Kubernetes, restricting access to a service based on pod labels. This is a fundamental step in securing inter-pod communication within your Kubernetes clusters.