Most cloud breaches I look at are not clever. An attacker gets hold of one set of credentials, and those credentials were allowed to do far more than the job ever needed.
The entry point is rarely the interesting part. A leaked access key, a phished session, a server-side request forgery that reaches the metadata endpoint: these happen. What decides whether that becomes a bad afternoon or a reportable incident is what the compromised identity was permitted to do. That is the blast radius, and you set its size long before the attacker arrives.
What IAM actually decides
Identity and access management answers one question on every request: can this identity perform this action, on this resource, under these conditions. Identities are people, roles, service accounts and workloads. Policies are the rules. The platform evaluates what the identity is allowed against any guardrails sitting above it, and returns allow or deny.
Get that model right and most of cloud security follows from it. Get it wrong and the strongest network controls you own become decoration, because the attacker is already inside, authenticated, and authorised. IAM is not a feature of cloud security. For practical purposes it is the perimeter.
Blast radius is the real metric
Blast radius is everything a single identity can reach if it is compromised. The size of that radius is set by you, in advance, through the permissions you attach. A role with wildcard actions on wildcard resources has an account-sized blast radius. A role scoped to read three specific buckets has a small one. Same breach, very different incident.
The part that makes it worse than it first looks is movement. An identity that can assume other roles inherits their reach. An identity that can pass a role to a service, through iam:PassRole, can often borrow that service's permissions. Chains like these turn a modest foothold into account-wide access without the attacker needing a single new exploit. They are just using the permissions you granted, in an order you did not anticipate.
Why least privilege is genuinely hard
If least privilege were easy, everyone would already have it. The honest reasons it slips:
You rarely know upfront exactly which permissions an application needs, so the quickest way to unblock a deployment is to grant broadly and move on. That breadth then sticks, because nothing forces it to narrow. Permissions accrete over time: every incident, every new feature, every "just attach the policy" leaves residue that nobody removes. The result is a large and growing gap between what an identity is granted and what it actually uses, and that gap is exactly where the risk sits.
The fix is data rather than guesswork. AWS IAM Access Analyzer and last-accessed information, and the equivalent reporting in Azure and Google Cloud, show you which permissions were really used over a window. You scope down to that, then review on a schedule, because usage changes and grants drift back upward.
The escalation paths people miss
Most privilege escalation in the cloud is not a vulnerability. It is a misconfiguration that the platform is happily honouring. The recurring ones:
- PassRole plus a service. An identity that can pass a privileged role to a compute or automation service can run code as that role. Scope
iam:PassRoletightly, or it becomes a quiet path to admin. - Policy self-service. Permissions like creating a new policy version or attaching a managed policy let a low-privileged role grant itself more. These belong to a very small set of identities.
- Wildcard trust. A role trust policy with a wildcard principal, or an over-broad
sts:AssumeRole, lets the wrong accounts or identities step into the role. Trust policies deserve the same scrutiny as permission policies. - The admin CI role. A pipeline role carrying AdministratorAccess so a deploy "just works" is a standing key to the account, sitting in a system that runs third-party code on every push.
The mechanisms that contain blast radius
None of these are exotic. They are the difference between an account that fails small and one that fails completely.
- Kill long-lived keys. Static access keys are the credential that shows up most often in breach write-ups. Use roles and short-lived STS credentials, and for CI use workload identity federation through OIDC instead of storing keys in the pipeline.
- Scope to actions, resources and conditions. Name the actions, name the resources, and add conditions such as MFA, source, or session tags where they fit. Wildcards are where blast radius hides.
- Put guardrails above identity policies. Service control policies in AWS Organizations, and management group policy in Azure, cap what is possible across an account no matter what an individual policy grants. A permission boundary does the same at the level of a single role.
- Separate humans from workloads, and make standing privileged access the exception. Just-in-time elevation, through Azure Privileged Identity Management or an approval step, means admin is something you hold for an hour, not a permanent attribute.
- Watch IAM itself. Who can assume what, who changed a policy, who used a sensitive action. CloudTrail and its equivalents are where escalation shows up first, if anyone is looking.
Best practices that survive production
- No long-lived access keys. Roles, short-lived STS credentials, and federation only.
- Scope every policy to specific actions and resources, with conditions where they fit. Treat a wildcard as something you have to justify.
- Use service control policies and permission boundaries as guardrails that cap blast radius even when an identity policy is too broad.
- Right-size from usage data, then review on a schedule. Granted is not the same as used, and grants drift upward over time.
- Separate human and workload identities, and make privileged human access just-in-time rather than standing.
- Monitor for escalation paths, not only for who holds admin. PassRole, policy editing, and trust policies are where it hides.
- Keep a break-glass account, locked down and alarmed, so least privilege never becomes the reason you cannot respond during an incident.
The part to take away
Least privilege is not about saying no. It is about deciding, before anything goes wrong, how far a single compromise can travel. Blast radius is a design choice you make when you write the policy, not a number you discover during the incident.
If you want one place to start, list the identities that can assume other roles or carry a wildcard, and look at them first. That is where your account is widest, and it is almost never where people are looking.