| name | aws-iam |
| description | Create and debug AWS IAM policies with least-privilege. Use on 'IAM policy', 'permission denied', 'access denied', 'not authorized', 'create role'. |
AWS IAM Skill
Create least-privilege IAM policies and debug access issues.
When to Use
- Create IAM roles/policies
- Debug "Access Denied" errors
- Audit existing permissions
- Set up cross-account access
- Configure service roles
Policy Principles
Least Privilege
- Specific actions, not
*
- Specific resources, not
*
- Add Condition blocks when possible
- Use managed policies over inline
Policy Structure
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DescriptiveName",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::bucket/path/*",
"Condition": {
"StringEquals": {"aws:PrincipalTag/team": "myteam"}
}
}]
}
Debug Access Denied
1. Identify the Error
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=<operation> \
--query 'Events[?contains(CloudTrailEvent, `AccessDenied`)]'
2. Simulate Policy
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789:role/MyRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::mybucket/mykey
3. Common Causes
| Error | Check | Fix |
|---|
| Explicit deny | Check SCPs, permission boundaries | Remove deny statement |
| Missing action | Policy doesn't include action | Add specific action |
| Wrong resource | ARN doesn't match | Fix resource ARN pattern |
| Condition failed | Condition block not met | Check tags, VPC, etc. |
Common Patterns
S3 Read-Only
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::bucket",
"arn:aws:s3:::bucket/*"
]
}
Lambda Execution Role
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/*"
}
EKS Pod Role (IRSA)
{
"Effect": "Allow",
"Principal": {"Federated": "arn:aws:iam::ACCOUNT:oidc-provider/OIDC"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"OIDC:sub": "system:serviceaccount:NAMESPACE:SA_NAME"
}
}
}
Cross-Account Access
{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::OTHER_ACCOUNT:root"},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {"sts:ExternalId": "UNIQUE_ID"}
}
}
Quick Commands
aws iam list-attached-role-policies --role-name MyRole
aws iam get-role-policy --role-name MyRole --policy-name MyPolicy
aws iam get-role --role-name MyRole --query 'Role.AssumeRolePolicyDocument'
aws sts get-caller-identity
Red Flags
"Action": "*" -> Too broad
"Resource": "*" -> Too broad
- No
Condition -> Consider adding
- Inline policies -> Use managed policies
- Long-lived access keys -> Use IAM roles