Skip to content

Network Policies

Kubernets NetworkPolicy

Every Kubernetes Container Network Interface (CNI) implements a standard Kubernetes NetworkPolicy controller. Kubernetes NetworkPolicy objects allow the user to apply two sorts of isolation for pods, ingress and egress. Native network policies operate at layer-3, and layer-4 allowing control based on pod labels, ip addresses, protocols (TCP, UDP, and SCTP) and ports. If no policy exists, either ingress or egress than traffic is unrestricted. You can choose to have one direction only as well.. an ingress policy but no egress, or the converse.

A basic network policy would look like:

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
In short, this policy applies to pods in the default namespace with the label "role=db" allowing ingress trafic from the network 172.17.0.0/16 (except 172.17.1.0/24), from pods with the label "project=myproject" and pods with the label "role=frontend". It also allows egress traffic to the CIDR range 10.0.0.0/24, TCP on port 5978 and nothing else.

Pretty cool eh ? NetworkPolicies are an easy, and powerful security measure. So.. what does Cilium do better ?

CiliumNetworkPolicy

CiliumNetworkPolicy objects have three big advantages over standard ones:

  1. They can operate at layer-7. This means you can allow GET requests, but not PUT. You can allow DNS queries of the hostname ubuntu.com, but not redhat.com.
  2. You can use FQDNs in rules. So you want to allow egress traffic to github.com ? In standard policies you would have to get every ip address and labouriously list them in a rule, and woe to you if they change. With CiliumNetworkPolicy you would just use the FQDN "githb.com"
  3. You can use Cilium's observability engine to generate CiliumNetworkPolicies, see Network Policy Editor

Lets have a look at a more complicated policy, including Cilium specific features and see if we can figure it out. As usual, click the for more information.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: gitlab-network-policy
spec:
  endpointSelector:
    matchLabels:
      app: gitlab (1)
  ingress:
    - fromEndpoints: (2)
        - matchLabels:
            app.kubernetes.io/name: traefik
            io.kubernetes.pod.namespace: traefik
      toPorts:
        - ports:
            - port: "80"
        - ports:
            - port: "81"
        - ports:
            - port: "22"
    - fromEndpoints: (3)
        - matchLabels:
            app: gitlab-runner
      toPorts:
        - ports:
            - port: "80"
  egress:
    - toEndpoints: (4)
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
          rules:
            dns:
              - matchPattern: "*"
    - toEndpoints: (5)
        - matchLabels:
            app: knot-master
            io.kubernetes.pod.namespace: dns
      toPorts:
        - ports:
            - port: "53"
              protocol: TCP
    - toEndpoints: (6)
        - matchLabels:
            app.kubernetes.io/component: ldap
            io.kubernetes.pod.namespace: ldap
      toPorts:
        - ports:
            - port: "1389"
    - toEndpoints: (7)
        - matchLabels:
            app: mailserver
            io.kubernetes.pod.namespace: mailserver
      toPorts:
        - ports:
            - port: "25"
        - ports:
            - port: "143"
        - ports:
            - port: "587"
        - ports:
            - port: "993"
    - toEndpoints: (8)
        - matchLabels:
            io.kubernetes.pod.namespace: traefik
      toPorts:
        - ports:
            - port: "8443"
    - toFQDNs: (9)
        - matchName: k8mail.mydomain
      toPorts:
        - ports:
            - port: "25"
        - ports:
            - port: "143"
        - ports:
            - port: "993"
        - ports:
            - port: "587"
    - toFQDNs: (10)
        - matchName: ldap.mydomain
      toPorts:
        - ports:
            - port: "389"
        - ports:
            - port: "636"
    - toFQDNs: (11)
        - matchName: version.gitlab.com
      toPorts:
        - ports:
            - port: "443"
  1. Apply this policy to pods with the label "app: gitlab"
  2. Allow ingress from the namespace traefik, pods labelled "app.kubernetes.io/name: traefik" to ports 22, 80, 81.
  3. Allow ingress from our own namespace, pods labelled "app: gitlab-runner" on port 80.
  4. Allow egress to the kubernetes builtin DNS server on UDP port 53, allowing queries to any domain name.
  5. Allow egress to the namespace dns, pods labelled "app: knot-master" to TCP/53.
  6. Allow egress to the namespace ldap, pods labelled "app.kubernetes.io/component: ldap" on port 1389.
  7. See if you can figure it out.
  8. See if you can figure it out.
  9. See if you can figure it out.
  10. See if you can figure it out.
  11. See if you can figure it out.

You can see why CiliumNetworkPolicies are leaps and bounds ahead of what you can do with stock NetworkPolicies.