AWS Security Hub · IAM
IAM.2: Policies attached directly to users do not scale or audit cleanly
Written and reviewed by Emnode · Last reviewed
What does AWS Security Hub IAM.2 check?
IAM.2 fails when an IAM user has any managed or inline policy attached directly to the user rather than inherited through a group. The control inspects every user and reports the ones carrying their own permissions.
Why does IAM.2 matter?
Per-user policies don't scale and they obscure intent. When permissions accrete one user at a time, nobody can answer "who has admin and why", least-privilege reviews become impossible, and a forgotten grant on a departed contractor lingers indefinitely. Anchoring access to groups gives every grant a documented, auditable reason to exist.
How do I fix IAM.2?
- List users with directly attached managed and inline policies to scope the work.
- Create groups that model real job functions and attach the policies there instead.
- Add each user to the right group, then detach the user-level policies once access is confirmed.
- For the longer term, move human identities to IAM Identity Center so AWS isn't where you manage people at all.
Remediation script · bash
# Generate a least-privilege policy from real usage, then promote it to default.
aws accessanalyzer start-policy-generation \
--policy-generation-details principalArn=arn:aws:iam::123456789012:role/DataPipelineWorker
aws iam create-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/DataPipelineWorkerPolicy \
--policy-document file://generated-policy.json --set-as-default
# Move a user's direct policy to a group: attach + add BEFORE detach, so there is no gap.
aws iam attach-group-policy --group-name developers \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
aws iam add-user-to-group --group-name developers --user-name nina
aws iam detach-user-policy --user-name nina \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Detach a broad CloudShell grant, then scope down anyone with a genuine need.
aws iam detach-group-policy --group-name developers \
--policy-arn arn:aws:iam::aws:policy/AWSCloudShellFullAccess Full walkthrough (console steps, edge cases and verification) in the lesson Enforce IAM least privilege.
Is IAM.2 a false positive?
A break-glass emergency user that must stay isolated from any group is a legitimate exception — document it and accept the finding rather than weakening the control.
More IAM controls
- IAM.1 A policy grants full "*" administrative privileges
- IAM.3 Long-lived access keys have not been rotated
- IAM.4 The root user still has long-lived access keys
- IAM.5 Console users without MFA are one phish from compromise
- IAM.6 The root user is not protected by hardware MFA
- IAM.7 The IAM password policy is too weak
- IAM.8 Unused IAM keys and passwords are waiting to be leaked
- IAM.9 The root user can sign in without MFA
- IAM.10 IAM user password policies should be strong (PCI DSS)
- IAM.19 MFA should be enabled for all IAM users
- IAM.21 Wildcard permissions grant far more access than intended
- IAM.22 IAM credentials unused for 45 days should be removed