Working with Cilium Network Policies

Working with Cilium Network Policies in Thalassa Cloud Kubernetes

Cilium Network Policies (CNPs) extend standard Kubernetes Network Policies with advanced features that enable fine-grained network security at the application layer. In Thalassa Cloud Kubernetes clusters using Cilium as the CNI, you can leverage Layer 7 (L7) filtering, DNS-based policies, identity-aware enforcement, and out-of-the-box network observability to implement Zero Trust networking principles.

While standard Kubernetes Network Policies operate at Layer 3 (IP addresses) and Layer 4 (ports and protocols), Cilium Network Policies add Layer 7 capabilities, allowing you to define rules based on HTTP methods, paths, headers, gRPC services, and Kafka topics. This enables you to enforce security policies that align with your application architecture, not just network topology.

Thalassa Cloud Kubernetes Service deploys Cilium with its Envoy-based Layer 7 (L7) proxy enabled on every node in your cluster. This built-in L7 proxy allows you to use Cilium’s advanced layer 7 policies—such as HTTP filtering (based on methods, paths, and headers), gRPC and Kafka-aware rules, and DNS-based controls—without any additional configuration. As a result, you can implement fine-grained security policies that operate at the application protocol level, making your cluster more secure and observant by design.

Prerequisites

  • Before working with Cilium Network Policies, ensure you have a running Kubernetes cluster in Thalassa Cloud with Cilium as the CNI. Cilium is the default CNI in Thalassa Cloud Kubernetes clusters. If you’re unsure, check your cluster’s CNI configuration in the Thalassa Cloud Console or verify with kubectl get pods -n kube-system | grep cilium.
  • You’ll need cluster access configured using kubectl. Use tcloud kubernetes connect to configure access, or set up kubeconfig manually. See the Getting Started guide for details.
  • Basic understanding of Kubernetes Network Policies is helpful. For an overview, see the Network Policies documentation.

Understanding Cilium Network Policies

Cilium Network Policies use the same Kubernetes resource model as standard Network Policies but with additional capabilities. They are defined using the CiliumNetworkPolicy CustomResourceDefinition (CRD) with the API version cilium.io/v2.

Key Differences from Standard Network Policies

FeatureStandard NetworkPolicyCiliumNetworkPolicy
Layer 7 FilteringNoYes (HTTP, gRPC, Kafka)
DNS-based RulesNoYes (FQDN matching)
Identity-based RulesNoYes (Cilium identities)
Egress to External ServicesLimitedAdvanced (FQDN, CIDR)
ObservabilityBasicAdvanced (Hubble)

Cilium Network Policy Structure

A Cilium Network Policy consists of:

  • endpointSelector: Selects the pods (endpoints) that the policy applies to, using label selectors
  • ingress: Defines allowed incoming traffic rules
  • egress: Defines allowed outgoing traffic rules
  • labels: Optional labels for policy organisation and management

Unlike standard Network Policies, Cilium Network Policies use endpointSelector instead of podSelector, though they function similarly.

Basic Cilium Network Policy Examples

Let’s start with some basic examples that demonstrate common use cases for Cilium Network Policies.

Example 1: Default Deny All Traffic

This policy blocks all network traffic to and from pods in a namespace unless explicitly allowed by other policies:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  endpointSelector: {}
  ingress: []
  egress: []

The empty endpointSelector: {} matches all pods in the namespace, and empty ingress and egress arrays deny all traffic.

Example 2: Allow DNS Queries

DNS is essential for service discovery. This policy allows pods to query CoreDNS:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  endpointSelector: {}
  egress:
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
        k8s:k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP
      - port: "53"
        protocol: TCP

This allows all pods in the production namespace to make DNS queries to CoreDNS pods in the kube-system namespace.

Example 3: Allow Traffic Between Namespaces

This policy allows pods with the label app: frontend in the production namespace to communicate with pods labeled app: backend in the backend namespace:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: frontend
  egress:
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: backend
        app: backend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP

Advanced Cilium Network Policy Features

Cilium Network Policies provide several advanced features that go beyond standard Kubernetes Network Policies.

Layer 7 (L7) HTTP Filtering

Cilium can inspect HTTP traffic and enforce policies based on HTTP methods, paths, and headers. This enables fine-grained control over API access.

Example: Restrict HTTP Methods

This policy allows only GET and POST requests to a web service:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: restrict-http-methods
  namespace: api
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
        - method: "POST"
          pathRegex: "^/api/v1/.*"

Example: Path-Based Access Control

This policy restricts access to specific API paths:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: restrict-api-paths
  namespace: api
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - pathRegex: "^/api/v1/public/.*"
        - pathRegex: "^/api/v1/users/.*"
          method: "GET"
          headers:
          - 'X-User-ID: ".*"'

This allows access to public endpoints and user-specific endpoints (with a user ID header) but blocks other paths.

DNS-Based Egress Policies

Cilium supports FQDN (Fully Qualified Domain Name) matching for egress policies, allowing you to control outbound traffic based on domain names rather than static IP addresses.

Example: Allow Egress to External APIs

This policy allows pods to connect to external APIs using FQDN matching:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-external-apis
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api-client
  egress:
  - toFQDNs:
    - matchName: "api.github.com"
    - matchPattern: "*.cloudflare.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP
  - toFQDNs:
    - matchName: "api.stripe.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP

The matchPattern allows wildcard matching, while matchName requires an exact match. Cilium resolves these FQDNs to IP addresses and enforces the policy accordingly.

DNS Resolution

Cilium resolves FQDNs to IP addresses and caches the results. If an external service changes its IP address, Cilium will update the policy enforcement after the DNS cache expires (typically 5 minutes).

Identity-Based Policies

Cilium assigns identities to endpoints based on labels, enabling identity-aware policy enforcement. This allows you to define policies based on what a pod is (its identity) rather than just where it is (its IP address).

Example: Identity-Based Access

This policy uses Cilium’s identity system to allow communication between specific service identities:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: identity-based-access
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: database
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: backend
        tier: application
    toPorts:
    - ports:
      - port: "5432"
        protocol: TCP

Cilium automatically assigns identities to pods based on their labels, making it easier to manage policies as pods are created, destroyed, or moved.

Kafka-Specific Policies

If you’re running Kafka in your cluster, Cilium can enforce policies based on Kafka topics, API keys, and client IDs.

Example: Restrict Kafka Topic Access

This policy restricts which Kafka topics a consumer can access:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: restrict-kafka-topics
  namespace: data-processing
spec:
  endpointSelector:
    matchLabels:
      app: kafka-consumer
  egress:
  - toEndpoints:
    - matchLabels:
        app: kafka-broker
    toPorts:
    - ports:
      - port: "9092"
        protocol: TCP
      rules:
        kafka:
        - apiKey: "fetch"
          topic: "user-events"
        - apiKey: "produce"
          topic: "processed-events"

This allows the consumer to fetch from user-events and produce to processed-events, but blocks access to other topics.

References and Further Reading