How to Threat Model a Kubernetes Cluster

Most threat models of apps that run on Kubernetes draw the app and stop there. The cluster appears as a box labelled "K8s", or as the background the services sit on. But Kubernetes isn't background. It's a second system with its own API, its own identities and its own data store, and an attacker who gets a foothold in one pod will look at that system before anything else.

This guide shows how to threat model the cluster itself: what to draw, which boundaries hold and which only look like they do, how to follow every identity that can act on the cluster, and how to turn what you find into scored, owned risks. The example is a small "shop" cluster on a managed service, but the steps apply to any cluster.

What Kubernetes changes in a threat model

If you've threat modeled microservices or cloud infrastructure, most of the method carries over. Four things are specific to Kubernetes, and they're where most cluster threat models fall short.

  • The API server is the control point for everything. Deploying, reading Secrets, opening a shell in a container and changing permissions are all API calls. Whoever can make the right call can change anything in the cluster, so the API server belongs at the centre of the diagram, not off to the side.
  • The defaults are open. Every pod can reach every other pod in every namespace until you add NetworkPolicies. Every pod gets a service account token mounted unless you turn it off. Nothing stops a privileged pod from being scheduled until you enforce a Pod Security Standard.
  • Identities are layered. Humans authenticate through your identity provider, workloads use service accounts, nodes have their own credentials, and all of them may map to cloud IAM roles. A threat model has to follow each one to see what it can reach.
  • Workloads share nodes. Containers on the same node share a kernel. If one escapes its container, it can reach everything else on that node: other pods' Secrets, the kubelet's credentials and the node's cloud identity.

Step 1: Decide what you're modeling

A cluster usually hosts more than one application, and the people who run the platform are often not the people who build the apps. Split the work the same way:

  • A platform model, owned by whoever runs the cluster: the control plane, nodes, networking, admission control, shared add-ons such as the ingress controller and GitOps tooling, and the cluster's link to the cloud account.
  • An application model for each app, owned by its team: its pods, service accounts, Secrets, NetworkPolicies and data flows. It treats the platform model's findings as assumptions ("pods can't run privileged in this namespace") rather than repeating them.

For a small team running a single cluster, one model is fine. Just keep the two halves in mind, because they change at different times and are reviewed by different people.

Step 2: Draw the cluster as a data flow diagram

Start with the usual data flow diagram elements, then add the parts of Kubernetes that an attacker would use. Here is the shop cluster: a customer-facing orders service, a payments service, a managed database, and the platform around them.

Data flow diagram of a Kubernetes cluster. Outside the cloud account: a customer's browser, an engineer using kubectl, and a CI/CD pipeline. Inside the cloud account, a control plane boundary holds the API server and etcd, which stores cluster state and Secrets. A worker node boundary holds the ingress controller, the kubelet, and a namespace called shop with an orders pod and a payments pod; the namespace is labelled as not a security boundary. An image registry, a managed database and the cloud metadata service sit inside the cloud account. Flows: HTTPS from the customer to the ingress controller, HTTP to the orders pod, pod to pod traffic to the payments pod, SQL to the database, kubectl over OIDC and deploys from CI to the API server, image pushes from CI and pulls by the kubelet, and exec, logs and pod specs between the API server and the kubelet. Two flows are highlighted in red: the orders pod calling the API server with its service account token, and node credentials from the metadata service that pods can reach.
The shop cluster. The two red, dashed flows are the ones most cluster diagrams leave out, and the ones attackers look for first.

What to include

  • The API server and etcd, even on a managed service where you never see etcd. Secrets live there, and so does every permission in the cluster.
  • Every way into the API server. Engineers with kubectl, the CI/CD pipeline or GitOps controller that deploys, and the pods themselves. A pod calling the API server with its service account token is a data flow, and usually the one that matters most.
  • The kubelet on each node type. It runs your containers, pulls images, and accepts exec and log requests.
  • Shared add-ons: the ingress controller, service mesh, certificate manager, GitOps tool, monitoring agents. They often run with cluster-wide permissions, so they're among the most privileged workloads you have.
  • Where images come from: the registry, and the pipeline that pushes to it. Our CI/CD threat modeling guide covers that side in depth.
  • The cloud metadata service and any cloud APIs pods can reach. They are how a cluster compromise becomes a cloud account compromise.

Model each workload as a process, but don't draw every replica or every microservice. A pod that has its own service account, its own Secrets or its own network exposure gets its own element; identical replicas don't.

Step 3: Mark the boundaries that actually hold

This is where cluster diagrams most often mislead. A namespace looks like a strong boundary on a diagram, and a container looks sealed. Neither is, by default. Write down what each boundary depends on.

BoundaryWhat it stops by defaultWhat it takes to rely on it
Internet to ingressOnly what the ingress controller and load balancer refuse.TLS, a patched ingress controller, and only the routes you mean to expose.
NamespaceName clashes, and RBAC bindings scoped to it. Not network traffic, not node sharing.Namespaced RBAC, a default-deny NetworkPolicy, and Pod Security Admission labels on every namespace.
ContainerOrdinary processes from seeing each other. It shares the node's kernel.Non-root, no privileged mode, no host mounts or host networking, dropped capabilities: the Restricted Pod Security Standard.
NodePods on other nodes, as long as nobody escapes to the host.Separate node pools for workloads that must not share a kernel, and nodes that can't use their credentials outside their own scope.
Control planeAnything RBAC denies. RBAC is only as tight as the bindings you've written.Private or allow-listed API endpoint, scoped RBAC, audit logging, and Secrets encrypted at rest.
Cloud accountCloud APIs, unless a pod can borrow the node's or its own cloud identity.Workload identity with narrow roles, and pods blocked from the node's metadata credentials.

If you can't tick the right-hand column for a boundary, draw it as a dotted line, as we did for the shop namespace, and model the threats as if it weren't there. That one change tends to surface most of a cluster's serious findings.

Step 4: Follow every identity

On Kubernetes, most serious attacks are a chain of borrowed identities: a bug in the app gives code execution, the pod's token gives API access, a broad role gives Secrets, and a Secret gives the cloud account. So list every identity that can act on the cluster, and for each one ask what it can reach.

IdentityQuestions to ask
HumansHow do they authenticate to the API server? Who has cluster-admin, and is it used day to day? Can a stolen laptop's kubeconfig be used from anywhere?
CI/CD and GitOpsWhat role does the deploy credential have? Could it be namespaced instead of cluster-wide? Who can change the pipeline or the Git repo it deploys from?
Service accountsDoes this pod need to call the API at all? If not, is the token mount turned off? If so, which verbs on which resources?
Controllers and operatorsWhich Secrets can the ingress controller, cert manager or GitOps tool read? Cluster-wide, or only where it needs to?
NodesWhat can the kubelet's credentials do? What cloud role does the node have, and can pods reach it?
Workload cloud identitiesWhich cloud roles are mapped to which service accounts? Could a pod in another namespace use the same role?

When you review RBAC, look past the obvious get secrets. The Kubernetes documentation on RBAC good practices lists permissions that are effectively admin even though they don't look it:

  • Creating pods (or Deployments, Jobs and anything else that creates pods) in a namespace lets you mount any Secret in that namespace and run as any service account in it. "Can deploy to shop" means "can read every Secret in shop".
  • escalate, bind and impersonate let an identity grant itself, or act as, something more powerful.
  • pods/exec and nodes/proxy give a shell in running containers, directly or through the kubelet.
  • Changing admission webhooks lets you see or alter every object as it's created.

Step 5: Walk each layer with STRIDE

The Kubernetes documentation's long-standing "4C" model splits cloud-native security into four layers: Cloud, Cluster, Container and Code. It works well as a checklist to make sure the model covers every layer. Apply STRIDE to the elements in each one.

LayerTypical threats
CloudPods reading the node's cloud credentials from the metadata service (Elevation of Privilege). Workload roles broader than the workload needs. The API endpoint reachable from the whole internet.
ClusterOver-broad RBAC bindings (Elevation of Privilege). Secrets in etcd without encryption at rest (Information Disclosure). No API server audit log (Repudiation). Outdated control-plane or node versions (Tampering).
ContainerPrivileged pods, host mounts or root users that make an escape easy (Elevation of Privilege). Images pulled by mutable tag from an unapproved registry (Tampering, Spoofing). No resource limits (Denial of Service).
CodeThe app bugs that start the chain: remote code execution, server-side request forgery, or a dependency with a known exploit. These belong in each application's own model.

Two technique catalogues are worth keeping open while you do this: Microsoft's Threat Matrix for Kubernetes and the Containers matrix in MITRE ATT&CK. Neither is a threat model, but both are good at pointing out a technique you forgot.

Step 6: Build attack trees for what matters most

STRIDE gives you a list of weaknesses. An attack tree shows how they combine into an incident. For a cluster, start with two or three goals an attacker would actually want, such as reading production Secrets, taking over the cloud account, or running code on every node. Here is the first one for the shop cluster.

  • ORGoal: read the payments service's Secrets
    • ANDUse the orders pod's identity
      • Get code execution in the orders pod (an app bug)
      • The service account token is mounted
      • Its role can read Secrets, or create pods, in the payments namespace
    • ANDEscape to the node
      • Run a privileged or host-mounting pod (no Pod Security Admission)
      • A payments pod is scheduled on the same node
    • ANDSteal a deploy credential
      • Compromise the CI/CD pipeline or its Git repo
      • The deploy credential is cluster-wide
    • Compromise a shared controller that can read every Secret, such as the ingress controller

An OR node succeeds if any child does; an AND node needs all of its children.

The last branch isn't hypothetical. In March 2025, CVE-2025-1974 ("IngressNightmare") let anyone who could reach the ingress-nginx admission webhook from the pod network run code in the controller, which by default could read Secrets across the whole cluster. That's the risk of a widely shared, highly privileged add-on, and it's why controllers belong on the diagram.

Look at the AND gates: each one is a place where a single control cuts off the branch. Turning off the token mount, or scoping the role to its own namespace, breaks the first branch even if the app has a bug. Our attack tree examples show the same pattern for other goals.

Step 7: Score the threats and give them owners

Here are ten threats from the shop cluster, scored with the likelihood and impact scales from our risk matrix guide: 1–4 Low, 5–9 Medium, 10–15 High, 16–25 Critical. Likelihood assumes the attacker needs the stated foothold first; that's why few cluster threats score 4 or 5 for likelihood on their own.

#ThreatLIScoreFirst fix
K1Orders pod's service account token can read Secrets in the payments namespace3515 HighTurn off the token mount; scope the role to its own namespace
K2SSRF in the orders app reaches the metadata service and gets the node's cloud credentials3412 HighBlock metadata from pods (on AWS, IMDSv2 with a hop limit of 1); use workload identity
K3No NetworkPolicies: a compromised orders pod reaches the payments pod's internal admin port3412 HighDefault-deny per namespace, then allow only the flows on the diagram
K4The CI/CD deploy credential is bound to cluster-admin2510 HighOne namespaced deploy role per app
K5Pod Security Admission isn't enforced, so a privileged pod can be scheduled and escape to the node2510 HighEnforce Restricted on app namespaces, Baseline at minimum elsewhere
K6The ingress controller can read Secrets in every namespace2510 HighPatch promptly; limit its Secret access to the namespaces it serves; don't expose its webhook to the pod network
K7The API server endpoint is public, so a leaked kubeconfig works from anywhere2510 HighPrivate endpoint or an IP allow-list; short-lived OIDC credentials
K8No resource limits: one pod can starve every workload on its node339 MediumRequests and limits, with a LimitRange per namespace
K9Images referenced by a mutable tag from a public registry248 MediumPin by digest; allow only your registry at admission
K10API server audit logging is off, so nobody can tell who read a Secret326 MediumTurn on audit logs for Secrets, exec and RBAC changes

What the scores tell you

  • Five of the ten have impact 5. In a cluster, many small misconfigurations end at the same place: every Secret, or the whole account. That's why the likelihood side, the footholds, is where most of the work goes.
  • The fixes are cheap compared with the risk. K1, K3 and K5 are each a few lines of YAML applied per namespace. Fixing them early also makes the scores of later findings fall, because they cut the chains in the attack tree.
  • K10 scores low but matters after an incident. Without audit logs, you can't tell whether K1 was ever used. Score it honestly, then fix it alongside the others anyway.

Record each threat in a risk register with an owner, a treatment and the evidence that the fix is in place. Platform findings belong to the platform team, app findings to the app team, which is where the split from step 1 pays off.

Managed clusters: what moves to the provider

On EKS, GKE or AKS, the provider runs the control plane and etcd. Patching the API server, protecting etcd and keeping control-plane components available are theirs. You can mark those threats as transferred, with a link to the provider's shared responsibility documentation as evidence.

Everything else stays with you: who can reach the API endpoint, every RBAC binding, NetworkPolicies, Pod Security Admission, workload settings, add-ons, the mapping from service accounts to cloud roles, and on most node types the nodes themselves. Check what your provider does by default for Secret encryption, metadata access from pods and audit logging rather than assuming; the answers differ between providers and have changed over time.

Common mistakes

  • Modeling the YAML instead of the system. Scanners that check manifests against a benchmark are useful, but they find settings, not attack paths. A cluster can pass a benchmark and still let one service account read every Secret.
  • Treating namespaces as tenants. Namespaces are fine for teams that trust each other. For customers or untrusted code, use separate node pools or separate clusters.
  • Leaving out the add-ons. Helm charts installed once from the internet often bring cluster-wide roles nobody reviewed. List them, and check their RBAC like any other identity.
  • Stopping at the cluster edge. The cloud account and the CI/CD pipeline are part of the cluster's attack surface. If the deploy credential is cluster-admin, the pipeline is as sensitive as the cluster.
  • Modeling once. Clusters change constantly. Revisit the platform model when you add an operator or a CRD, onboard a new team to the cluster, change how identities map to cloud roles, or upgrade across a major version. Our guide to when to re-threat-model has the general triggers.

Frequently asked questions

Is a Kubernetes namespace a security boundary?

Not on its own. A namespace scopes names, RBAC bindings and quotas, but pods in different namespaces share nodes and, without NetworkPolicies, can reach each other freely. It becomes a useful boundary only when RBAC, NetworkPolicies and Pod Security Admission are all scoped to it. For hostile tenants, use separate node pools or separate clusters.

Do I need to threat model a managed cluster like EKS, GKE or AKS?

Yes. The provider runs the control plane and etcd, so those threats move to the provider. You still own who can reach the API server, RBAC, NetworkPolicies, workload settings, node configuration on most node types, and how cluster identities map to cloud IAM. Those are where most cluster incidents start.

What is the 4C model of Kubernetes security?

Four layers, each depending on the one outside it: Cloud, Cluster, Container and Code. It is a useful checklist for making sure a threat model covers every layer, but it does not show how an attacker moves between layers. Use a data flow diagram and attack trees for that.

Which framework lists Kubernetes attack techniques?

Two are widely used: Microsoft's Threat Matrix for Kubernetes and the Containers matrix in MITRE ATT&CK. Both are catalogues of techniques. Use them to check your attack trees for missing branches, not as the threat model itself.

Running payments or customer data on Kubernetes for a regulated business? See threat modeling for fintech, or our guide to multi-tenant SaaS if several customers share one cluster.

Model your cluster in ThreatTree

ThreatTree's DFD editor has Kubernetes cluster, node, pod and container elements next to its AWS, Azure and GCP ones, with trust boundaries you can draw around them. Once the cluster is on the diagram, the attack tree generator drafts attack trees from the components you've drawn for you to review, and the threats you keep feed a scored risk register.

Get started free Or start from a DFD template →

Not ready to sign up? Get new threat-modeling guides by email instead.