Skip to main content

Detect lateral movement

An intruder is already inside. The perimeter told you nothing, because nothing crossed it — the traffic that matters is one workload reaching another, and on a Kubernetes cluster that looks like an ephemeral IP talking to another ephemeral IP.

The reason east-west detection is hard is not visibility. It is that raw flows between pod addresses are unreadable: by the time you investigate, the pod is gone and the address has been reused.

Give the flows names

The service graph resolves addresses to identity — which workload, which namespace, which app — so a flow reads as checkout talked to the payments database rather than as two IPs.

That mapping is built by the operator from the cluster's own Pods and uploaded for agents to consume:

ProducerBuildsFrom
Identity producerpod IP → workload, namespace, appCluster Pods
Edge producerthe allow-list of intended conversationsCluster NetworkPolicy

Compare observed against declared

The second producer is what turns visibility into detection. Your NetworkPolicy already describes which workloads are supposed to talk to each other; compiling it into declared edges means an observed flow can be checked against it.

A conversation nobody declared is the signal. It is not proof of compromise — but it is a short, reviewable list, which is more than a flow log gives you.

Turning it on

The producers are operator flags, exposed as chart values. Both need an API key with identity:write:

operator:
identityProducer:
enabled: true
edgeProducer:
enabled: true
apiKeySecret:
name: synapse-operator-api-key

Deploy the agent as a DaemonSet so every node observes its own traffic — see Helm Charts.

Check your chart version

The producers need pods, namespaces and networkpolicies in the operator's ClusterRole. Charts before synapse-stack 0.6.0 granted none of them, so both producers fail on a default install. Synapse Operator has the detail and the workaround.

Where this stops working

  • Identity is as good as your labels. Workloads that are not labelled meaningfully resolve to names that do not help an investigation.
  • A cluster with no NetworkPolicy has no declared edges, so there is nothing to compare against and the edge producer contributes nothing.
  • The baseline is periodic. The full upload is a cold-start and resync source; freshness between uploads comes from event-driven deltas. A pod that lives and dies inside a gap may not resolve.
  • This is detection, not prevention. Enforcement still happens in the kernel, through the firewall. Seeing an undeclared conversation does not stop it.
  • Multiple clusters need --cluster-id. Without it they share one path and the last writer wins.

See also