Ask a team to threat model their cloud and you will usually get a network diagram: subnets, security groups, a load balancer, some arrows. It is a perfectly good drawing of a data centre, and it models the wrong thing. In a data centre, an attacker has to travel — through the firewall, across the network, onto the host. In the cloud, an attacker with the right credential does not travel at all. They make an API call from their own laptop, and every subnet boundary you drew is irrelevant to it, because the call never touches your network.
That is the shift the model has to absorb. Your infrastructure has two surfaces, not one: the data plane, where traffic flows between running things, and the control plane, where the provider's API creates, reads, modifies, and destroys those things. The network diagram describes the first. Almost every cloud incident worth the name happens on the second.
The short version: Draw the shared responsibility line first, so you model what you configure rather than what the provider operates. Then make identity the perimeter: accounts, subscriptions, or projects are the hard boundaries, and every role, key, and trust relationship is a boundary crossing. Ask three things of each identity — who can obtain it, what it can reach, and whether you would notice it being used from somewhere unexpected. Finally, map the escalation paths that need no vulnerability at all, because in the cloud the most common breach is a permission working exactly as written.
Draw the shared responsibility line first
Before anything else, mark on the diagram where the provider's responsibility ends and yours begins, because half of an unproductive cloud modelling session is people raising threats against things they cannot influence. The line moves depending on what you consume, and that movement is the point: the more managed the service, the less surface you own — and the more your remaining surface is pure configuration.
| What you run | Provider handles | Yours to model |
|---|---|---|
| Virtual machines | Hypervisor, physical hosts, facility | Guest OS and patching, everything on the instance, the network rules around it, and the identity attached to it |
| Managed containers | Control plane of the orchestrator, node infrastructure in fully managed modes | Images, workload identity, namespace and cluster-role permissions, what a compromised pod can reach |
| Managed databases | Engine patching, replication, backup machinery | Who can connect, who can read the backups, whether it is reachable publicly, and who holds the keys |
| Serverless functions | Runtime, scaling, isolation | The code, its dependencies, its execution role, its triggers, and its environment variables |
| Object storage | Durability, the storage layer itself | Bucket policy, public access settings, encryption and key access, lifecycle and versioning |
Notice what is in the right-hand column: almost nothing there is a software vulnerability. It is all configuration and permission. That is the shape of cloud risk, and it is why a threat model beats a scanner here — a scanner can tell you a bucket is public, but only a model tells you that the bucket being public matters because of what a different system writes into it.
Identity is the perimeter
The single most useful move in a cloud threat model is to stop treating the network as the boundary and start treating identity as one. A role that can read every object in storage does not care which subnet you are in. A key with administrative rights is not made safer by a firewall. So the boundaries you draw on the data flow diagram should be identity boundaries, with the network as a secondary layer rather than the primary one.
The vocabulary differs by provider but the structure does not, which is worth putting in front of a mixed-cloud team so the session does not stall on terminology:
| Concept | AWS | Azure | GCP |
|---|---|---|---|
| Hard isolation boundary | Account | Subscription | Project |
| Grouping / policy inheritance | Organizations & OUs | Management groups | Folders & organization |
| Workload identity | IAM role on the resource | Managed identity | Service account |
| Control-plane audit trail | CloudTrail | Activity Log | Cloud Audit Logs |
| Key custody | KMS key policy | Key Vault access policy / RBAC | Cloud KMS IAM |
The first row is the one people underuse. An account, subscription, or project is the only boundary the provider enforces for you at the control plane. Everything finer — a role, a policy, a tag condition — is a rule you wrote and can get wrong. So when the model says two systems must not reach each other, the strongest available answer is usually that they live in different accounts, not that a policy says no.
Three questions for every identity
Enumerate the identities — human users, workload identities, CI credentials, third-party integrations — and put each through the same three questions. This is the core of the exercise and it goes faster than it sounds, because most systems have fewer distinct identities than they have components.
- Who can obtain it? Not who is supposed to use it — who can. Anyone who can run code on the instance holds its role. Anyone who can merge to the deploy branch holds the pipeline's credential. Anyone who can read the state file may hold whatever is in it.
- What can it reach? Follow the permission to its actual end, including the second hop: this role can invoke that function, and that function's role can read the database. Effective permission is transitive, and the diagram should show that chain rather than one hop at a time.
- Would you notice? If this identity were used at 3am from an unfamiliar location to enumerate storage, is that an alert, a log entry nobody reads, or nothing at all? This is the question that converts a scary finding into a cheap mitigation, and it usually has the worst answer of the three.
Write the answers next to the identity, not next to the resource. Cloud resources are ephemeral — instances come and go, functions get redeployed — but identities and their permissions are durable, which makes them the stable thing to model. A threat model written against instance IDs is stale in a week; one written against roles survives.
Where cloud credentials actually leak
Since the control plane is reached with credentials, the highest-value part of the model is tracing every place a credential can be obtained. These are the recurring ones, and they are worth walking as a checklist because teams reliably remember two or three of them and forget the rest.
| Source | What to ask |
|---|---|
| The instance metadata service | The classic path: a server-side request forgery in your application becomes a request to the local metadata endpoint, which returns the instance's credentials. Is the hardened, session-authenticated version of the metadata service enforced rather than merely available? Does the workload's role justify the blast radius of that trade? |
| Infrastructure-as-code state | State files routinely contain generated secrets in plain text. Where is the state stored, who can read that location, and is it encrypted with a key that is itself access-controlled? |
| Pipeline variables and OIDC trust | Covered in depth in the CI/CD guide, but the cloud-side half belongs here: which repository, branch, and environment can assume your deployment role, and is the trust condition specific enough that a fork or a pull request cannot satisfy it? |
| Environment variables and function config | Anyone who can read the resource's configuration through the control plane can read its environment, which means a "read-only" permission is frequently a credential-disclosure permission. |
| Images and snapshots | Machine images, container images, and volume snapshots carry whatever was on disk at build time. Are any shared publicly or across accounts, and does anything in the layer history contain a key? |
| Logs and error output | Request logs, debug output, and exception traces that capture headers or tokens, forwarded to a log platform with a much broader audience than the system that produced them. |
| Long-lived static keys | Any key that does not expire is a key that outlives the person, laptop, or contract it was issued for. Where do they exist, who rotated them last, and what would rotation break? |
Escalation without an exploit
This is the section that changes how a room thinks. In the cloud, privilege escalation frequently requires no vulnerability whatsoever — just permissions that combine into something nobody intended. The provider is not malfunctioning; it is doing precisely what the policy says.
The recurring shapes are worth learning to spot on sight. An identity that can attach or modify policies can grant itself anything. An identity that can pass a role to a compute service can launch something that runs as a more privileged identity, even without holding that identity itself. An identity that can edit a trust policy can add itself as a principal. An identity that can write to infrastructure code that a pipeline applies has, in effect, the pipeline's permissions. An identity that can create a new version of a function can execute code as that function's role.
None of these is a bug. Each is a legitimate permission that becomes an escalation when it lands on an identity that also has a path to reach it. This is exactly the structure an attack tree is for — take one goal such as read the production database from outside the account and enumerate the branches: a leaked human credential, an application flaw reaching the metadata service, a pipeline credential, a permission chain from a low-privilege role. What the tree shows is which branches terminate at a real control and which terminate at nothing, and it consistently surfaces a path nobody in the room had considered because each individual permission looked reasonable in isolation.
The STRIDE sweep, at cloud altitude
| Category | What to ask of cloud infrastructure |
|---|---|
| Spoofing | What can assume each role, and how specific is the condition? Is there a federation trust that a third party controls? Can a workload in one environment obtain an identity intended for another? |
| Tampering | Who can modify infrastructure outside the pipeline? Are manual console changes possible, and would they be detected or quietly overwritten at the next apply? Who can alter a policy, a security group, or a key? |
| Repudiation | Is the control-plane audit log enabled in every region and account, written somewhere the audited identities cannot delete, and actually retained? A trail an admin can erase is not a trail. |
| Information disclosure | What is reachable publicly — storage, databases, management endpoints, snapshots? What does a read-only role actually expose, given configuration often contains secrets? |
| Denial of service | Beyond availability: what can a credential destroy, and what can it spend? Deletion of storage, of backups, or of the keys that decrypt them is the irreversible one, and runaway cost is a real availability threat with a financial shape. |
| Elevation of privilege | The escalation shapes above. Also: can any identity reach another account, subscription, or project — and was that path deliberate? |
Keys are an access control, not a checkbox
Encryption at rest is on by default nearly everywhere now, which makes it easy to tick and move on. The useful question is never whether data is encrypted but who can decrypt it, because the key policy is an access control sitting behind the resource policy — and the two frequently disagree.
Ask who can use each key, who can administer it, and who can delete or disable it. A provider-managed key means the provider's own service permissions govern access, which is usually fine and occasionally not — notably when the threat you are modelling is a broadly-permissioned internal role, since that role may be able to read the data through the service without ever touching a key policy. Customer-managed keys give you a second, independent gate, and the model should say plainly whether you are relying on it. Then ask the availability question nobody asks until it is urgent: what happens if the key is deleted or its policy is broken, and is that recoverable?
Model the change surface, not the snapshot
Cloud infrastructure is defined in code and rebuilt constantly, so a model describing the current arrangement of resources describes something that will not exist next month. Model the process that produces the infrastructure instead. Who can change the definitions, what reviews that change, what credential applies it, and what happens to a change made outside that path?
This is where the cloud model meets the pipeline model, and the two should reference each other rather than duplicate. The pipeline guide covers who can change what runs; this one covers what the resulting credential can reach. The interesting threats live exactly at that join: a pipeline with permission to modify its own permissions is the cloud version of a program that can rewrite its own security policy.
Drift matters too. If manual changes are possible, the running infrastructure and its definition diverge, and every conclusion in your model quietly stops being true. A team that detects drift has a genuine detective control worth recording; a team that cannot is modelling a system it cannot see.
What to record
Record findings against identities and configurations rather than resources, since those are what persist. Where a finding is structural — "the application role can read every object in the bucket, not just its own prefix" — write it once as an architectural entry rather than once per service.
Then write down the assumptions, which in cloud are unusually load-bearing and unusually invisible: which accounts you believe are isolated, which identities you believe nothing external can assume, which data you believe never leaves a region, which permissions you believe are unused. That last one deserves a review date, because permissions granted for a migration two years ago are still there, and the gap between granted and used is where most of the excess blast radius lives. Natural triggers for revisiting are a new account, a new federation trust, a new managed service, a new region, and any change to the pipeline's role — plus, as always, whatever the mitigation entries claim, since a cloud control that cannot be evidenced from the audit log is a control that only exists in the document.
Where cloud threat models go wrong
- Modelling the network and calling it done. Subnets and security groups constrain the data plane. The control plane does not pass through them.
- Treating the provider's compliance as your control. Their certifications cover their responsibilities. Everything in the right-hand column of the responsibility table is still yours.
- Enumerating resources instead of identities. Resources are ephemeral; roles and permissions are the durable structure.
- Stopping at the first permission hop. Effective access is transitive, and the second hop is where the surprise usually is.
- Ignoring the audit log's own permissions. If the identities being audited can disable or delete the trail, you have logging but not evidence.
- Forgetting deletion and cost. Both are availability threats, both are reachable from an ordinary credential, and one of them is irreversible.
- Modelling one account when you run twelve. The interesting questions are usually between accounts, not inside one.
The test of a cloud threat model is simple: can you say, for any given entry point — a leaked developer credential, an SSRF in a web tier, a compromised build — exactly what an attacker reaches, in how many steps, and what would show up in the log while they did it. A model that answers that is worth the afternoon. A network diagram, however carefully drawn, cannot answer it at all.
Regulated workloads add residency and key-custody constraints that belong on the diagram as explicit boundaries rather than assumptions. See threat modeling for SaaS and for fintech, or start from a pre-labelled DFD in the free threat modeling templates.