Skip to main content
The Topology tab is the map every other Security view drills out of. One call — GET /api/supervisors/<supervisor>/security/flows/topology?since=1h — returns the whole graph for the window: nodes for everything that talked, edges for every conversation, each edge carrying the verdict Cilium reached and whether a policy was responsible for it. A busy supervisor produces a graph of real size. A one-hour window on a supervisor running four guest clusters returned 160 nodes and 604 edges — which is exactly why the filters below matter more than the picture. The Topology view — scope bar, window and verdict filters, rollup tiles (workloads, edges, denied flows, problem ports) and the flow graph

Nodes are not all pods

The graph deliberately mixes eight node kinds, because an operator asking “what does this talk to” does not care that half the answer is not a pod: Each node carries its listening ports, which is often the most useful part of the payload — it is the observed service surface of that workload, not what a manifest claims:
peers is the discriminator worth scanning for: a port reached by one peer is a dependency, a port reached by dozens is a service. l7Protocol appears only where Cilium’s L7 layer saw the traffic. Nodes that a policy selects also carry coveredBy:

Edges carry the verdict

Every edge is a (source, destination, port, protocol) roll-up with an action — the single most important field on the page: The distinction between allow and unprotected is the point of the whole view: both mean traffic got through, but only unprotected means nothing would have stopped it. On the sample graph above, 518 edges were allow, 34 policy-protected, 30 reject, and 22 unprotected.
A denied edge looks like this — note bytes: 0, because a connection that never established moves no payload:
outcome adds the connection-level result (established, delivered, policy-denied) where conntrack could determine it, and trafficDirection (INGRESS/EGRESS) appears on edges observed from one side only.

Narrowing the graph

The full graph is a starting point, not an answer. The controls map one-to-one onto query parameters: by=node is the fastest way to answer “is this a workload problem or a machine problem”. origin exists because a vcluster’s pods are synced onto the host as ordinary pods that can carry byte-identical labels to a native twin — see Pipeline & runtime. Two helper endpoints back these controls: flows/dimensions enumerates the nodes and interfaces present in the window, and flows/labels returns the label keys and values actually seen, so a filter never offers a value that returns nothing.

Coverage has known blind spots

Edge coverage is computed by matching observed workloads against the workloads that applied policies select. That matching has three documented limits, and every one of them makes the graph look less protected than it is:
Identity indexing keys off four labels. A workload is only recognized through vm.kubevirt.io/name, app.kubernetes.io/name, app, or k8s-app. A pod labelled only with a taxonomy of your own — class=frontend, say — is invisible to coverage, so its edges stay unprotected even when a policy is correctly enforcing on it. Always give workloads an app label in addition to whatever else you select on.
  • Only Cilium policies count. Coverage walks CiliumNetworkPolicy and CiliumClusterwideNetworkPolicy. A standard networking.k8s.io/v1 NetworkPolicy is enforced by Cilium perfectly well but is not counted — edges it protects render as unprotected. If you want the graph to reflect a policy, express it as a CNP (or apply both).
  • Shared chart labels collapse. When several tiers of one Helm chart share a single app.kubernetes.io/name, they fold into one coverage key while the graph still shows each Deployment separately. Intra-namespace edges between those tiers can stay unprotected although enforcement is correct.
When the graph and reality disagree, the authoritative check is the policy itself: flow matches counts real flows the policy matched, and drift compares what a policy declares against what was observed. The edge quality gauge on this tab tells you the other half of the trust question — what fraction of edges have both flow and byte data behind them.

From the graph to everything else

The graph is where investigations start and then leave. A node with a suspicious ingress port leads to Ingress Forensics; an external peer that shouldn’t be there leads to Egress Forensics; an unprotected edge you want to close leads to author mode on this same tab, which is covered in Network policies.
Celum AI reads the same graph. get_flow_topology returns nodes and edges with all the filters above, get_policy_coverage returns which policies cover which workloads, and get_workload_identity resolves the label set a selector would have to match.