IAM Core Concepts
| Concept | Description |
|---|---|
| User | A real person or a service account |
| Group | A collection of users — attach policies to the group |
| Role | Temporary credentials assumed by AWS services such as EC2 and Lambda |
| Policy | A JSON document of allow/deny rules |
| Permissions boundary | The maximum permission scope a role can have |
JSON Policy Structure
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadOnly",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
},
{
"Sid": "DenyDeleteEverything",
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "*"
}
]
}Deny always takes precedence over Allow.
Least-Privilege Policy Examples
EC2 Read-Only
JSON
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:List*"
],
"Resource": "*"
}]
}Full Access to a Specific S3 Bucket Only
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-specific-bucket",
"arn:aws:s3:::my-specific-bucket/*"
]
}
]
}Creating an EC2 Instance Role
Bash
# Create the role
aws iam create-role \
--role-name EC2-S3-ReadOnly \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# Attach the policy
aws iam attach-role-policy \
--role-name EC2-S3-ReadOnly \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Create and attach the instance profile
aws iam create-instance-profile --instance-profile-name EC2-S3-ReadOnly
aws iam add-role-to-instance-profile \
--instance-profile-name EC2-S3-ReadOnly \
--role-name EC2-S3-ReadOnlyMFA Enforcement Policy
Block permissions on console access when MFA is not enabled:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyWithoutMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}IAM Best-Practices Checklist
Bash
# Check root account usage
aws iam get-account-summary | grep RootAccess
# Find users without MFA
aws iam generate-credential-report
aws iam get-credential-report | python3 -c "
import sys, base64, csv, io
data = eval(sys.stdin.read())
report = base64.b64decode(data['Content']).decode()
reader = csv.DictReader(io.StringIO(report))
for row in reader:
if row['mfa_active'] == 'false' and row['password_enabled'] == 'true':
print(row['user'])
"
# Access keys unused for 90+ days
aws iam list-users --query 'Users[*].UserName' --output text | \
xargs -I{} aws iam list-access-keys --user-name {} --query \
'AccessKeyMetadata[?Status==`Active`].[UserName,AccessKeyId,CreateDate]' \
--output table- Enable MFA on the root account, then do not use it
- Use roles instead of personal access keys
- Regularly delete unused credentials
- Apply account-level guardrails with AWS Organizations SCPs
Editorial note
AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us
Topic-related official docs (auto-linked · not per-claim sources)AWS documentation ↗OWASP documentation ↗
Questions & answers
Ask a question about this guide. We'll review and reply.