If you’ve inherited AWS accounts with IAM policies full of wildcards—"Action": "*" or "Resource": "*"—you’re not alone. I’ve audited dozens of accounts where quick prototyping made it to production, leaving massive security gaps. In this post, I’ll walk through exactly how to identify overly permissive policies and systematically right-size them using AWS IAM Access Analyzer and service last-accessed data.
The Problem
You find IAM policies like this in production:
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
or slightly more restricted:
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
These policies create unnecessary blast radius. If credentials are compromised, an attacker has access to everything. You need to right-size them, but you don’t want to break anything in the process.
| Risk Type | Description |
|---|---|
| Credential Compromise | If access keys leak, attacker has full account permissions |
| Insider Threat | Malicious employee can access any resource without restrictions |
| Third-Party Risk | Contractors/vendors with these keys have excessive access |
The goal: replace wildcards with minimal necessary permissions.
Why Does This Happen?
- Copy-pasted from Stack Overflow: Quick fix during prototyping that never got refactored
- Lack of review process: Policies weren’t audited before pushing to production
- Over-engineering for “least privilege”: Developers err on the side of too much access rather than debugging permission errors
- Lack of access analyzer awareness: Teams don’t know how to use tooling to right-size policies
- Business pressure: “Move fast” culture that doesn’t prioritize security hardening
The Fix
Step 1: Find All Overly Permissive Policies
Start by identifying which roles/users have wildcard permissions:
# List all inline policies on a role
aws iam list-role-policies \
--role-name MyRole \
--output text
# Get the policy document
aws iam get-role-policy \
--role-name MyRole \
--policy-name MyPolicy \
--query 'RolePolicyDocument' \
--output text | jq .
Look for these red flags:
"Action": "*""Action": "service:*"(e.g.,"s3:*")"Resource": "*"combined with broad actions- Missing ResourceArn conditions
Step 2: Use IAM Access Analyzer to Check for Public Access Issues
IAM Access Analyzer identifies public access problems automatically:
# Create or get an analyzer (if not already created)
aws accessanalyzer list-analyzers \
--output text
# Create an analyzer if needed
aws accessanalyzer create-analyzer \
--analyzer-name account-analyzer \
--type ACCOUNT \
--output text
# List findings
aws accessanalyzer list-findings \
--analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/account-analyzer \
--query 'findings[?resourceType==`AWS::IAM::Role`]' \
--output text
Access Analyzer shows policies that allow public access or access from other accounts — immediate red flags for overly permissive policies.
Step 3: Check Service Last Accessed Data
Find out which services and actions the role actually uses:
# Generate service last accessed report for a role
aws iam generate-service-last-accessed-details \
--arn arn:aws:iam::123456789012:role/MyRole \
--output text
# This returns a job-id. Poll for completion.
aws iam get-service-last-accessed-details \
--job-id 12345678-1234-1234-1234-123456789012 \
--output text
This shows which services the role has accessed in the last 90 days. Services not in this list are candidates for removal from the policy.
Example output format shows:
s3:GetObject— last accessed 5 days agoec2:DescribeInstances— last accessed 30 days agoiam:AttachUserPolicy— never accessed
Any service/action never accessed can be removed from the policy.
Step 4: Validate Policies with Access Analyzer
Use Access Analyzer to validate policy syntax and find issues:
# Validate an **IAM** policy document
aws accessanalyzer validate-policy \
--policy-document file://my-policy.json \
--policy-type IDENTITY_POLICY \
--output text
This shows warnings about:
- Overly permissive actions (e.g.,
*) - Empty resource lists
- Missing resource constraints
- Unreachable policy statements
Step 5: Right-Size the Policy Incrementally
Create a minimal policy based on last-accessed data:
# Old overly permissive policy
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
# New right-sized policy (based on actual usage)
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
Key improvements:
- Specific actions instead of
s3:* - Specific resources instead of
* - Only permissions actually used
Step 6: Test the New Policy
Before replacing the old policy, test the new one using Policy Simulator:
# Simulate the old broad policy
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/MyRole \
--action-names s3:GetObject s3:PutObject s3:DeleteObject \
--resource-arns arn:aws:s3:::my-bucket arn:aws:s3:::my-bucket/* \
--output text
Compare results between old and new policies. The new policy should allow exactly the same actions used in production.
Step 7: Deploy the New Policy
Once tested, update the role:
# Update the inline policy
aws iam put-role-policy \
--role-name MyRole \
--policy-name MyPolicy \
--policy-document file://new-minimal-policy.json
Or create a managed policy for better lifecycle management:
# Create new managed policy
aws iam create-policy \
--policy-name S3ReadWriteMinimal \
--policy-document file://new-minimal-policy.json \
--output text
# Attach to role
aws iam attach-role-policy \
--role-name MyRole \
--policy-arn arn:aws:iam::123456789012:policy/S3ReadWriteMinimal
# Detach old overly permissive policy
aws iam detach-role-policy \
--role-name MyRole \
--policy-arn arn:aws:iam::aws:policy/S3FullAccess
Audit Workflow Summary
- Identify overly permissive policies → Search for
"Action": "*"and"Resource": "*" - Check Access Analyzer findings → Look for public access warnings
- Get service last-accessed data → See which services actually used in 90 days
- Build minimal policy → Only include used services/actions and specific resources
- Validate new policy → Use Policy Simulator to verify functionality preserved
- Deploy incrementally → Test in non-production first
- Monitor CloudTrail → Watch for new access denied errors after deployment
Is This Safe?
Right-sizing policies is safe if you follow the workflow above. Using Policy Simulator to test is completely safe — it’s read-only. Deploy to non-production environments first before production rollout.
Key Takeaway
Service last-accessed data is your best friend when right-sizing IAM policies. Generate it for every role, remove services/actions never accessed in 90 days, and use specific resource ARNs instead of wildcards. In my experience, overly permissive policies can be cut down by 60-80% using this approach without breaking anything. The hardest part isn’t the technical work — it’s changing the culture from “give admin access and debug later” to “minimal access by default.”
Have questions or ran into a different IAM issue? Connect with me on LinkedIn or X.