Kubernetes Series: Control Pods Traffic with Network Policies

Explaining k8s NetworkPolicies resources, Pod isolation based on network traffic types, a NetworkPolicy manifest and NetworkPolicy fields with some practical examples

Sylia CHIBOUB
Cloud Native Daily

--

Introduction

This article covers the k8s Network Policies. Section 1 explains k8s NetworkPolicies resources, Section 2 goes through Pod isolation based on network traffic types. Section 3 illustrates a NetworkPolicy manifest and finally Section 4 details NetworkPolicy fields with some practical examples.

1. Network Policies

NetworkPolicies provide the ability to control Pods network traffic at the IP address or port level (OSI layer 3 or 4) through specifying how a Pod is allowed (or not) to communicate with other network entities. [1]

OSI Model [2]

It is worth noting that NetworkPolicies only apply to Pods and are not relevant to other k8s resources.[1] They only restrict Pod-to-Pod communication when necessary.

Entities that a Pod can communicate with are identified through a combination of the following 3 identifiers: [1]

  • Other Pods that are allowed (exception: a Pod cannot block access to itself)
  • Namespaces that are allowed
  • IP blocks (exception: traffic to and from the node where a Pod is running is always allowed, regardless of the IP address of the Pod or the node)

Prerequisites

NetworkPolicies are implemented by the k8s network plugins such as Calico. To use NetworkPolicies, you must be using a networking solution which supports NetworkPolicy. Creating a NetworkPolicy resource without a controller that implements it will have no effect.[1]

2. Pods Isolation

There are two sorts of isolation for a pod:

Isolation for ingress: ingress refers to inbound traffic received by the Pod.

Isolation for Egress: egress refers to outbound traffic sent by the Pod.

They are declared independently, and are both relevant for a communication from one Pod to another. [1]

2.1 Isolation for Ingress

By default, a Pod is non-isolated for ingress. All inbound connections to the Pod are allowed. [1]

A Pod is isolated for ingress if there is any NetworkPolicy that both selects the Pod and has ingress attribute in its policyTypes (NetworkPolicy Fields are presented later on). [1]

When a Pod is isolated for ingress, the only allowed connections into the pod are those from the Pod's node and those allowed by the ingress list of some NetworkPolicy that applies to the Pod for ingress. [1]

For a connection from a source Pod to a destination Pod to be allowed, both the egress policy on the source Pod and the ingress policy on the destination Pod need to allow the connection. If either side does not allow the connection, it will not happen

Important

NetworkPolicies do not conflict.They are additive. If any policy or policies apply to a given pod for a given direction, the connections allowed in that direction from that pod is the union of what the applicable policies allow. Thus, order of evaluation does not affect the policy result. [1]

2.2 Isolation for egress

By default, a Pod is non-isolated for egress. All outbound connections are allowed. [1]

A Pod is isolated for egress if there is any NetworkPolicy that both selects the Pod and has egress attribute in its policyTypes (NetworkPolicy Fields are presented later on)[1]

When a Pod is isolated for egress, the only allowed connections from the pod are those allowed by the egress list of the NetworkPolicy that applies to the Pod for egress. [1]

3. The NetworkPolicy YAML Manifest

Here’s an example of a NetworkPolicy taken from Kubernetes Official Documentation [1]

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

The above NetworkPolicy performs the following:

  • It isolates Pods with the role=db label in the default namespace for both ingress and egress traffic.
  • It defines a set of ingress rules that allow connections to Pods with the role=db label in the default namespace on TCP port 6379 only from:

- Any pod in the default namespace with the label role=frontend

- Any pod in a namespace with the label project=myproject

- Entities with IP addresses in the CIDR 172.17.0.0/16 except 172.17.1.0/24

  • It defines a set of egress rules that allow connections from Pods with the role=db label in the defaultto CIDR 10.0.0.0/24 on TCP port 5978 .

4. The NetworkPolicy Fields

  • podSelector : selects the grouping of Pods based on their Labels in the same namespace as the NetworkPolicy. An empty podSelector selects all pods in the namespace.[1]
# this pod selector selects all pods having the label role: db
# in the NetworkPolicy namespace

...
spec:
podSelector:
matchLabels:
role: db
...

Important

# this pod selector selects all pods in the NetworkPolicy namespace
podSelector: {}
  • policyTypes : It may include either Ingress, Egress, or both. it indicates whether or not the NetworkPolicy applies to Ingresstraffic to selected pod, Egresstraffic from selected pods, or both.[1]
...
policyTypes:
- Ingress
- Egress
...

Important

If no policyTypes are specified on a NetworkPolicy then by default Ingress will always be set and Egress will be set if the NetworkPolicy has any Egressrules

if a policyTypes is defined with Ingress or Egress but no Ingress or Egress fields are specified later then by default Ingress and Egress traffic will be denied. Here’s an example:

# Deny all ingress traffic: 
# ---------------------------

# This NetworkPolicy selects all pods in the NetworkPolicy namespace
# but does not allow any ingress traffic to those pods.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
# Deny all egress traffic: 
# ---------------------------

# This NetworkPolicy selects all pods in the NetworkPolicy namespace
# but does not allow any egress traffic to those pods.

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
# Deny all ingress and all egress traffic

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
  • Ingress : Includes a list of allowed ingress rules. Each rule allows traffic which matches both the from and ports sections. The example policy contains a singleingress rule, which matches traffic on a single port, from one of three sources: ipBlock, namespaceSelector and podSelector.[1]
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

Important

If no rule is specified within the Ingress as follows. Then, all ingress traffic will be allowed. Here’s an example that allows all incoming ingress traffic to all pods in the NetworkPolicy namespace.

# Allow all ingress traffic to all pods within the NetworkPolicy namespace
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- {}
  • ipBlock This selects particular IP CIDR ranges to allow as ingress sources or egress destinations. These should be cluster-external IPs, since Pod IPs are ephemeral and unpredictable.[1]
...
...
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
  • namespaceSelector This selects particular namespaces having specific labels for which all Pods should be allowed as ingress sources or egress destinations.[1]
# There's two ways of targeting labeled namespaces:

# OPTION 1: target the namespace labeled project:myproject
ingress:
- from:
...
- namespaceSelector:
matchLabels:
project: myproject

# OPTION 2: target namespaces having project:myproject1 and app:myproject2 labels
- namespaceSelector:
matchExpressions:
- key: project
operator: In
values: ["myproject1", "myproject2"]

Important

namespaceSelectorand podSelector: A single to/from entry that specifies both namespaceSelector and podSelector selects particular Pods within particular namespaces. Be careful to use correct YAML syntax. For example:[1]

...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...

This policy contains a single from element allowing connections from Pods with the label role=client in namespaces with the label user=alice. [1]

But the following policy is different:

...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...

It contains two elements in the from array, and allows connections from Pods in the same namespace as the NetworkPolicy having the label role=client, or from any Pod in any namespace labeleduser=alice.[1]

  • Port this field allows Igress or Egress traffic to a specific port or to a range of port. For exampe:

# allow ingress traffic on port 6370
...
ingress:
- from:
...
ports:
- protocol: TCP
port: 6379
# allow ingress traffic on port range 32000 - 32768
...
ingress:
- from:
...
ports:
- protocol: TCP
port: 32000
endPort: 32768
  • Egress : Each NetworkPolicy may include a list of allowed egress rules. Each rule allows traffic which matches both the to and ports sections. The example policy contains a single rule, which matches traffic on a single port to any destination in 10.0.0.0/24.[1]
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978

Important

If no rule is specified within the Egress as follows. Then, all egress traffic will be allowed. Here’s an example that allows all incoming egress traffic to all pods in the NetworkPolicy namespace.

# Allow all egress traffic 
---

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress

Conclusion

The primary goal of this article was to give a deeper understanding of the Kubernetes NetworkPolicy resource through practical examples. This has been accomplished by giving a general overview of the k8s NetworkPolicies and then getting more practical through different examples.

References

[1] Network policies (2023) Kubernetes. Available at: https://kubernetes.io/docs/concepts/services-networking/network-policies/ (Accessed: 08 June 2023).

--

--

Sylia CHIBOUB
Cloud Native Daily

Supporting Open Source and Cloud Native as a DevOps Engineer