The NetworkPolicy Object via API

So far, we've focused on enabling communication: getting traffic to Pods via Services and Ingress. However, in many environments, especially multi-tenant clusters or applications handling sensitive data, controlling which Pods are allowed to communicate with each other is just as critical for security and isolation. By default, Kubernetes follows an "allow all" model within the cluster network – any Pod can attempt to connect to any other Pod's IP address and port, regardless of namespace.

Kubernetes Network Policies provide a mechanism to restrict this traffic flow at Layer 3 (IP address) and Layer 4 (TCP/UDP ports). Think of them as distributed, application-aware firewalls for your Pods. Like Ingress, NetworkPolicy resources are definitions of desired state; they require a Network Plugin (CNI) that supports and enforces Network Policies (e.g., Calico, Cilium, Weave Net, Antrea; basic plugins like Flannel typically do not enforce them).

In this chapter, we'll explore how to define these traffic rules using the NetworkPolicy resource and manage them programmatically with client-go.

The NetworkPolicy Object via API (networking.k8s.io/v1.NetworkPolicy)

NetworkPolicy resources belong to the networking.k8s.io API group, version v1. When using client-go, you'll work with the networkingv1.NetworkPolicy struct (k8s.io/api/networking/v1). These policies are namespaced, meaning a NetworkPolicy created in one namespace can only directly affect Pods within that same namespace.

The core logic resides within the spec field (v1.NetworkPolicySpec).

spec.podSelector (metav1.LabelSelector)

This is fundamental. It selects the group of Pods within the policy's namespace to which this specific NetworkPolicy applies.

  • Mechanism: Uses standard Kubernetes label selectors (like those used by Services or Deployments).

  • Targeting: The ingress and egress rules defined within this policy will control the traffic for the Pods matching this selector.

  • Empty Selector ({}): An empty podSelector (e.g., podSelector: {} in YAML) selects all Pods in the namespace. This is often used for defining default deny or default allow policies for the entire namespace.

  • Omission: If podSelector is omitted entirely, the policy applies to no Pods (which is rarely useful).

# Example NetworkPolicy Spec - PodSelector
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-api-policy
  namespace: prod-api
spec:
  podSelector:
    matchLabels:
      app: user-service # This policy applies to Pods with label 'app=user-service'
      tier: backend
  # ... policyTypes, ingress, egress rules follow ...

spec.policyTypes ([]v1.PolicyType)

This field specifies whether the policy applies to ingress (incoming) traffic, egress (outgoing) traffic, or both, for the Pods selected by podSelector.

  • Values: Can be a list containing Ingress, Egress, or both.

  • Ingress: The policy rules will define what incoming traffic is allowed to the selected Pods. If policyTypes includes Ingress but the ingress rules section is empty or omitted, it means no ingress traffic is allowed to the selected Pods (unless allowed by another policy).

  • Egress: The policy rules will define what outgoing traffic is allowed from the selected Pods. If policyTypes includes Egress but the egress rules section is empty or omitted, it means no egress traffic is allowed from the selected Pods (unless allowed by another policy).

  • Omission: If policyTypes is omitted:

    • If spec.ingress rules are present, it defaults to [Ingress].

    • If spec.egress rules are present (and no ingress rules), it defaults to [Egress].

    • If both ingress and egress rules are present, it defaults to [Ingress, Egress].

    • It's generally recommended to be explicit and always include policyTypes for clarity.

# Example NetworkPolicy Spec - PolicyTypes
spec:
  podSelector:
    matchLabels:
      app: user-service
  policyTypes: # Be explicit
  - Ingress    # This policy will define rules for incoming traffic
  - Egress     # This policy will ALSO define rules for outgoing traffic
  ingress:
  # ... ingress rules ...
  egress:
  # ... egress rules ...

spec.ingress ([]v1.NetworkPolicyIngressRule)

This optional list defines the allowed incoming traffic rules for the Pods selected by podSelector. If this field is present (even if empty), only traffic matching at least one rule in this list is allowed ingress. If policyTypes includes Ingress but spec.ingress is omitted or empty, all ingress traffic is blocked (for the selected pods).

Each NetworkPolicyIngressRule specifies:

  • from ([]v1.NetworkPolicyPeer): A list of sources from which traffic is allowed. If omitted or empty, it allows traffic from all sources (subject to ports restrictions). Each NetworkPolicyPeer can specify sources by:

    • podSelector (*metav1.LabelSelector): Allows traffic from Pods (in any namespace, unless restricted by namespaceSelector) matching this label selector.

    • namespaceSelector (*metav1.LabelSelector): Allows traffic from any Pod within namespaces matching this label selector. Often used with podSelector to restrict it to the policy's own namespace or specific other namespaces. An empty selector ({}) selects all namespaces.

    • ipBlock (*v1.IPBlock): Allows traffic from a specific range of IP addresses (CIDR notation). Useful for allowing traffic from outside the cluster or specific node IPs. ipBlock has cidr (string) and optional except ([]string) fields.

  • ports ([]v1.NetworkPolicyPort): A list specifying the destination ports and protocols on the target Pod (the one selected by spec.podSelector) that the allowed sources can connect to. If omitted or empty, traffic is allowed to all ports on the target Pod from the specified sources. Each NetworkPolicyPort can specify:

    • protocol (*v1.Protocol): TCP, UDP, SCTP. Defaults to TCP if omitted.

    • port (*intstr.IntOrString): Specifies the port number or named port (defined in the Pod spec) on the target Pod. If omitted, matches any port (for the specified protocol).

    • endPort (*int32): If set, defines a port range (inclusive) along with port. Requires CNI support.

Ingress Logic: Traffic is allowed if it originates from a source matching any entry in any from block AND targets a destination port matching any entry in the corresponding ports block within the same rule.

# Example NetworkPolicy Spec - Ingress Rule
spec:
  podSelector:
    matchLabels: {app: database}
  policyTypes: [Ingress]
  ingress:
  - from: # Allow traffic FROM these sources...
    - podSelector: # ...from pods with label 'app=backend' in the same namespace
        matchLabels: {app: backend}
    - namespaceSelector: # ...OR from pods in any namespace labeled 'monitoring=true'
        matchLabels: {monitoring: true}
    ports: # ...TO these ports on the database pods
    - protocol: TCP
      port: 5432 # Allow connection to TCP port 5432

spec.egress ([]v1.NetworkPolicyEgressRule)

This optional list defines the allowed outgoing traffic rules from the Pods selected by podSelector. If this field is present, only traffic matching at least one rule in this list is allowed egress. If policyTypes includes Egress but spec.egress is omitted or empty, all egress traffic is blocked.

Each NetworkPolicyEgressRule is structured similarly to ingress rules:

  • to ([]v1.NetworkPolicyPeer): A list of destinations to which traffic is allowed. If omitted or empty, allows traffic to all destinations (subject to ports restrictions). Uses the same podSelector, namespaceSelector, and ipBlock fields as the ingress from section to specify allowed destinations.

  • ports ([]v1.NetworkPolicyPort): A list specifying the destination ports and protocols on the remote endpoint that the selected Pods are allowed to connect to. If omitted or empty, traffic is allowed to all ports on the specified destinations. Uses the same protocol, port, and endPort fields as the ingress ports section.

Egress Logic: Traffic is allowed if it targets a destination matching any entry in any to block AND targets a destination port matching any entry in the corresponding ports block within the same rule.

# Example NetworkPolicy Spec - Egress Rule
spec:
  podSelector:
    matchLabels: {app: backend}
  policyTypes: [Egress]
  egress:
  - to: # Allow traffic TO these destinations...
    - podSelector: # ...to pods with label 'app=database' in the same namespace
        matchLabels: {app: database}
    ports: # ...ON these destination ports
    - protocol: TCP
      port: 5432 # Allow connection TO TCP port 5432 on database pods
  - to: # Also allow traffic TO...
    - namespaceSelector: {} # ...any pod in any namespace...
    ports: # ...but ONLY for DNS resolution
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53
  - to: # Also allow traffic TO...
    - ipBlock: # ...external monitoring service IP range
        cidr: 198.51.100.0/24
    ports: # ...ON port 443
    - protocol: TCP
      port: 443

Default Behaviors (Important!)

  • No Policies: If no NetworkPolicies select a particular Pod, all ingress and egress traffic is allowed to/from that Pod (default allow).

  • Policy Selects Pod: As soon as any NetworkPolicy selects a Pod for a given direction (Ingress or Egress via policyTypes), that Pod becomes isolated for that direction. All traffic in that direction is denied by default, unless it is explicitly allowed by a rule in at least one of the policies applying to that Pod.

Understanding the structure of the NetworkPolicy resource, especially the selectors (podSelector, namespaceSelector) and the ingress/egress rules, is key to defining fine-grained network security within your cluster. Next, we'll look at how these rules interact and some common patterns.

Last updated

Was this helpful?