Least Privilege is the foundational security principle that every identity (user, role, service) should have only the minimum permissions required to perform its intended function. Nothing more.
In AWS, this means writing IAM policies that specify exact actions on exact resources instead of using wildcards. A Lambda function that reads from one S3 bucket should have s3:GetObject on that specific bucket ARN, not s3:* on *.
The most common failure I see is the "temporary" wildcard that becomes permanent. A team is under deadline pressure, an application fails with an AccessDenied error, and someone attaches AdministratorAccess or writes "Action": "s3:*", "Resource": "*" to unblock the release. The intent is to tighten it later. Nobody ever does, because the application works and the policy is invisible until an audit or an incident.
The damage shows up when that identity is compromised. A classic chain: an EC2 instance runs a web application with a server-side request forgery (SSRF) flaw, the attacker uses it to query the instance metadata service and steal the instance role credentials, and because the role carries a wildcard policy instead of the three actions the application actually needs, the attacker can now enumerate and exfiltrate every S3 bucket in the account. The vulnerability was in the application, but the blast radius was defined entirely by the IAM policy. With a least-privilege role, the same SSRF would have exposed read access to one bucket.
The other recurring failure is granting broad iam:* permissions to humans or CI/CD pipelines. Any identity that can create policies, attach policies, or pass roles can usually escalate itself to administrator, so a sloppy IAM grant silently converts every other narrow policy in the account into a formality.
IAM can tell you which services an identity was actually allowed to use versus which ones it really touched. Generating that report is a two-step, asynchronous process:
aws iam generate-service-last-accessed-details --arn arn:aws:iam::123456789012:role/my-app-role
This returns a JobId. Retrieve the report with:
aws iam get-service-last-accessed-details --job-id <job-id>
The output lists every service the role's policies allow and the last time each was actually accessed. Services that were never accessed in the tracking period are prime candidates for removal from the policy. You can pass --granularity ACTION_LEVEL on the generate call to get last-accessed data per action for supported services, which is even more useful for trimming policies. For net-new policies, use IAM Access Analyzer policy generation, which builds a policy from the CloudTrail activity of the role over a period you choose.
Perfect least privilege on day one is not realistic, and chasing it can paralyze delivery. What works in practice:
Resource to specific ARNs even when you cannot yet narrow the action listiam:, sts:AssumeRole, kms:Decrypt, and data-read actions on sensitive storesIs least privilege the same thing as zero trust?
No. Least privilege is about the size of the permission set an identity holds. Zero trust is a broader architecture principle that says no request should be trusted based on network location alone and every request must be authenticated and authorized. Least privilege is one ingredient of a zero trust design, not a synonym.
Does least privilege apply to AWS managed policies?
AWS managed policies like ReadOnlyAccess or PowerUserAccess are convenient but deliberately broad, because they have to serve every customer. They are acceptable for exploration in sandbox accounts. For production workloads, write customer managed policies scoped to the exact resources the workload uses.
How do I find over-permissive identities I already have?
Combine three sources: IAM Access Advisor (services granted but never used), IAM Access Analyzer unused access findings (unused roles, unused permissions, and unused access keys), and CloudTrail analysis for the actions actually called. Start with identities that hold administrative or IAM permissions, since those carry the escalation risk.
A JSON document that defines permissions - which actions are allowed or denied on which AWS resources, and under what conditions.
An advanced IAM feature that sets the maximum permissions an IAM entity can have, acting as a ceiling on what identity-based policies can grant.
An organization-wide guardrail that restricts what actions member accounts can perform, regardless of their IAM policies.
The scope of impact when a security incident occurs - how many resources, accounts, or users are affected. Smaller blast radius means better security posture.
A security model where no user, device, or network is trusted by default - every access request is verified regardless of location, using identity-based policies and continuous validation.
Toc Consulting: AWS Security & Cloud Architecture
Our team helps engineering teams secure and architect AWS the right way: assessment in week one, a prioritized action plan in week two.