soft guideINFRASTRUCTURE & ADVISORY

Note 04

Capabilities: a network policy model that does not drift

A default-deny network policy model where workloads declare dependencies by label, destinations admit the same label, and a narrowly privileged pipeline applies it all.

Why hand-written policies drift

A caller's egress rule and the destination's ingress rule are usually written in different places by different people. A rule gets copied with more than it needs. A "temporary" broad rule stays because nobody can prove what removing it would break.

Capabilities

Every tenant namespace is deny-by-default. A shared dependency is a capability: a reusable policy component the namespace lists, and a label the workload carries. The destination admits callers by the same label, so the two sides cannot drift apart.

# destination side: admit any caller that carries the capability, from any namespace
ingress:
  - fromEndpoints:
      - matchLabels: { netpol.cell.io/svc-payments: "true" }
        matchExpressions:
          - { key: k8s:io.kubernetes.pod.namespace, operator: Exists }
    toPorts: [{ ports: [{ port: "8080", protocol: TCP }] }]

The matchExpressions line is not decoration: without it, a fromEndpoints selector silently means "only this namespace".

Where the line is

The test for "is this a capability" is: if a second workload carried this label, would that be correct? Shared services and infrastructure pass it. A destination only one workload uses, such as its own bucket or database, does not: it lives as a private policy in that namespace, so a label can never grant access to someone else's data.

Guardrails on the guardrails

Who may talk to whom becomes readable in one directory and reviewable in one pull request.

Start a conversation

Bring your infrastructure
into focus.

Tell me what you are building, operating, or trying to improve.

Let’s talk