Least privilege in practice: cutting an AWS role down without breaking production
Nobody sets out to grant a role full administrator access
It happens the way most cloud security problems happen. A deployment fails on a Friday, somebody widens a policy to unblock it, and the comment that says tighten this later outlives the person who wrote it. Three years on, the role has forty permissions and nobody can say which eight it actually uses.
The fix is not a policy document. It is a method you can run on a Tuesday without taking production down. Here is the one we use.
Start from what the role did, not from what it is allowed to do
The permissions attached to a role tell you the ceiling. They tell you nothing about the floor. The useful question is narrower: in the last ninety days, which API calls did this role actually make?
AWS already answers this. IAM Access Analyzer generates a policy from CloudTrail history, and IAM's last-accessed data shows which services a role has not touched in months. Both are free, and both are more honest than any architecture diagram.
Read the generated policy and expect it to surprise you. A role that everyone believed was read-only turns out to write to a bucket once a quarter. A role nobody could explain turns out to be doing nothing at all.
Watch out for the long tail
Ninety days of history misses the annual job. It misses the disaster-recovery path that has never run. It misses the quarterly reconciliation that touches three services nothing else touches.
So before you cut anything, ask the team one question: what does this system do that it does not do every week? Write the answers down. Those paths are the ones that break at the worst possible time, because nobody tests them and nobody remembers them.
Cut in two moves, never one
The mistake is replacing the broad policy with the narrow one and waiting to see what breaks. Something always breaks, usually in the dark, usually in the path nobody remembered.
Do it in two moves instead.
Move one: observe without enforcing. Attach the narrow policy alongside the broad one, and leave the broad one in place. Nothing changes functionally. What changes is that you can now compare intent against behaviour. Set an alarm on any call the narrow policy would have denied. Let it run for a full cycle of your business — a month if you close books monthly, a quarter if the quarterly job matters.
Move two: remove the broad policy. By now your alarm has either been silent, in which case the cut is safe, or it has told you precisely which permission you were about to remove by mistake. Either outcome is a good one, and neither involved an outage.
This takes longer than one change window. That is the point. The speed you lose in the method, you gain back by never doing an emergency rollback at 2am.
Write it as code, or it will not survive
A permission tightened in the console is a permission that drifts back. Somebody will widen it next Friday and there will be no record of why it was narrow.
Put the policy in your infrastructure repository. Raise it as a pull request. Make the pull request description say what the role does and what it must never do. That description is the only documentation anyone will read, because it sits next to the thing it describes, and because the next person to widen the policy has to walk past it.
Prefer conditions over new roles
When two consumers need almost the same access, the instinct is to create a second role. Resist it for a moment. Often a condition on the existing policy — a source account, a tag, a resource prefix, a requirement for a particular session context — expresses the difference more precisely than a whole new identity does.
Fewer roles that are each precisely scoped beat many roles that are each vaguely scoped. Every role you add is one more thing somebody has to reason about during a review.
What your reviewers are actually asking for
When a security reviewer asks about least privilege, they are rarely asking for a policy document. They are asking a simpler question that most teams cannot answer: if this credential leaked right now, what would the attacker reach?
A role whose policy was generated from observed behaviour, narrowed in two moves, and committed as code lets you answer that question in a sentence and show the evidence. That is what ends the conversation. Not a diagram, and not an assurance.
Where to start this week
Do not begin with the hardest role. Begin with the one that scares you most if it leaked, which is usually a deployment role or a data-processing role rather than a human one. Generate its policy from CloudTrail. Read it. Ask the team about the long tail. Run the two moves.
One role, done properly, teaches your team the method. The second one is faster, and by the fifth it is just how your team works.
If you would rather have someone run this across your estate and hand you the ranked list, our free Well-Architected Review starts with exactly this question.
Ready to Unlock the Full Power of AWS?
Let’s talk about your cloud goals — no pressure, no hard sells. We’ll audit your setup, suggest improvements, and help you scale smarter.





