Finding and fixing over-permission
Lesson 4 of 4 in Designing and Reviewing Access.
Designing access well is half the task; the other half is finding the access you already granted and should not have. IAM Access Analyzer is the service the exam expects for this, and it is worth knowing that it is not one feature but five, answering different questions.
The engine underneath is automated reasoning — mathematical analysis of what the policies can permit, not observation of what has happened. That distinction decides questions: Access Analyzer reports that a bucket policy allows an external principal whether or not anyone ever used it. It is a statement about the policy, not about the traffic.
- External access findings — resource policies (including role trust policies) that permit a principal outside your zone of trust, which is the account or organization you chose when creating the analyzer. The external access analyzer is the free one.
- Unused access findings — roles, IAM user access keys and passwords, and permissions that have gone unused past your tracking period, with policy recommendations that narrow the grant.
- Internal access findings — which principals inside your organization can reach a nominated critical resource. Together with external findings on the same zone of trust, this gives the complete answer to "who can read this bucket?"
- Policy validation — findings while you author: errors, security warnings, suggestions, general warnings.
- Custom policy checks — PASS/FAIL gates for a pipeline.
| Finding type | What it analyses | Scope you choose | The caveat |
|---|---|---|---|
External access | Resource-based policies — bucket policies, key policies, queue and topic policies, role trust policies, secret policies | Account or organization (the zone of trust) | It reports possible access, not actual access. Deliberate sharing — a partner’s audit role — must be handled with archive rules, or the live list becomes noise. Re-analysis after a policy change can take up to about 30 minutes. |
Unused access | Activity history of roles, users, credentials, and granted permissions | Account or organization, plus a tracking period in days | A permission unused for 90 days may still be needed at year end. Set the tracking period to your audit cycle, and exclude known-seasonal principals by tag rather than forcing a false positive. |
Internal access | All IAM policies, to map access paths to resources you nominate | Account or organization | You choose the resources to monitor, so the answer is only as complete as that list. |
Policy validation | A policy document you are authoring | The document itself | Advisory at authoring time — it does not gate anything by itself. |
Custom policy checks | A proposed policy against a reference policy or a forbidden action list | Per invocation, in CI or an IDE | A pass is only as strong as the checks you wrote — |
You have found over-permission. What do you actually do?
Interactive decision tree — outcomes:
- Archive it, with a rule and a reason
Intended sharing is not a defect, but an un-archived finding trains people to ignore the list. Create an archive rule matching that principal and resource so future identical findings are suppressed, and record why. Then tighten the grant itself if you can —
aws:PrincipalOrgID,aws:SourceArn, or a narrower action list usually survives the review better than the original. - Narrow the resource policy, then verify
Edit the bucket, key, queue, or trust policy to remove the external principal — or, better, replace the broad principal with a condition that cannot drift:
aws:PrincipalOrgIDfor organization-only access, an exact role ARN,sts:ExternalIdfor a vendor. Then re-run the analyzer and confirm the finding resolves, and consider an RCP so a future bucket owner cannot reintroduce it. - Identify the principal before changing anything
An unrecognised external account in a trust or resource policy is an incident until proven otherwise. Check CloudTrail for whether it has ever been used and for who added the statement (
PutBucketPolicy,UpdateAssumeRolePolicy). If it was never used and nobody can explain it, remove it and keep the evidence. If it has been used, this is an incident-response question, not a tidying question. - Lengthen the tracking period rather than guessing
Set the tracking period to cover a full business cycle — six months or a year — and exclude the known-seasonal principals by tag. Removing a permission that turns out to be the quarterly close is a self-inflicted outage, and it teaches the organization to distrust the tooling. Where the risk is high and the use rare, replace the standing permission with a just-in-time path: a separate role, assumed with approval, rather than a permission nobody exercises.
- Apply the recommended narrowing, then re-measure
Take the policy recommendation from the unused-access finding, review it against intent, simulate it, and deploy it behind a
CheckNoNewAccessgate. For an unused role, delete it — but check for references first (resource policies, trust relationships, instance profiles, IaC templates). For unused credentials, deactivate before deleting so a surprise is recoverable. - Fail the build
Run
CheckNoNewAccessagainst the current policy andCheckAccessNotGrantedagainst your forbidden-action list in the pipeline. A change that was meant to narrow but widens anything fails before it merges — which is the only point at which fixing it is cheap. - Revoke the sessions, not just the credential
For an IAM user: deactivate then delete the access key, and reset the console password. For a role, the thing you cannot do is un-issue the credential — it stays valid until it expires. Authorization is still evaluated against the role’s current policies on every call, so stripping the role does stop the attacker; it also stops every legitimate user of that role, which on a shared role is rarely acceptable. The surgical form is an inline policy denying all actions when
aws:TokenIssueTimeis earlier than now — exactly what the console’s "Revoke sessions" action attaches, as a policy namedAWSRevokeOlderSessions— so outstanding sessions die and sessions assumed afterwards keep working. Then audit what the session did: CloudTrail filtered to that assumed-role ARN and session name.
Two remediation details are worth stating precisely, because both are frequently got wrong.
Revoking a role's sessions is not the same as removing its policies — though not for the reason usually given. The common claim is that a session's permissions are fixed when it is created. They are not: every request is authorized against the role's current policies, so detaching a policy does reach a session already running, after a short propagation delay. What you cannot do is un-issue the credential — it stays valid until it expires, which is why a leaked session is dangerous at all.
The real objection to stripping the role is blast radius. Detaching its policies denies every legitimate user of that role at the same instant, and a shared role cannot simply be left bare. The documented remedy is surgical instead — a time-based deny attached to the role:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "RevokeOlderSessions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"DateLessThan": { "aws:TokenIssueTime": "2026-10-20T14:30:00Z" }
}
}]
}
Every session issued before that instant is denied everything; sessions created afterwards are unaffected — the console's version even covers about thirty seconds into the future to absorb policy propagation. That selectivity is the point, and it is the answer to "a session is compromised and the attacker is active" precisely because it does not take the role away from everyone else. Two limits to carry: you cannot revoke the session of a service-linked role, and a role created from an IAM Identity Center permission set is not editable in IAM — you revoke that session in Identity Center instead. Note also that aws:TokenIssueTime is absent from requests signed with long-term IAM user credentials, so this deny never touches those; there, you deactivate the access key.
Verification is part of remediation. After narrowing, re-run the analyzer and confirm the finding clears; after deleting a role, confirm nothing referenced it; after revoking, confirm with CloudTrail that calls from that session now fail. A remediation nobody verified is a remediation nobody can evidence to an auditor — and Domain 2 will ask you to evidence it.
Finally, the blind spots worth carrying into the exam. Access Analyzer reads policies, so it does not know that a role nobody can assume is harmless, or that a public bucket is a deliberate website origin. The policy simulator does not evaluate RCPs and uses no production context values. Unused-access findings cannot distinguish "abandoned" from "rare". None of these are reasons not to use the tools; they are the reasons a human reviews the output.
Interactive sorting exercise: Each task needs one specific capability. Sort them.
Key terms: IAM Access Analyzer, External access findings, Unused access findings, IAM policy simulator, Custom policy check
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.