How to use
- Identify the service (S3, SQS, SNS, KMS, STS, EC2, VPC endpoints, Organizations).
- Decide the policy type: identity, resource, trust, or guardrail (boundary, SCP, session, endpoint).
- Run the rapid triage checklist at the bottom before editing anything.
Policy types
1) Identity-based policy (User/Group/Role permissions)
- Attached to IAM user/group/role
- Grants/denies API actions
2) Resource-based policy (resource permissions)
Common examples:
- S3 bucket policy
- SNS topic policy
- SQS queue policy
- KMS key policy
- Lambda permission policy (AddPermission)
3) Trust policy (AssumeRole policy)
- Controls who can assume a role
- Very common trick: correct principal but wrong condition (ExternalId/MFA/OIDC claims)
4) Permissions boundary
- Caps maximum permissions for a principal
- Common “why is my Allow not working?” cause
5) SCP (Service Control Policy) (Organizations)
- Org/OU/account-level deny guardrail
- Deny wins over everything
6) Session policy (AssumeRole session)
- Passed during AssumeRole; further restricts the session
7) VPC endpoint policy
- Restricts what can pass through an endpoint (Gateway or Interface)
8) KMS grants
- Temporary delegated permissions; common in services that need to use a CMK
Policy blocks (copy/paste)
A) Trust policies (AssumeRole)
A1) Cross-account trust (basic)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAssumeFromAccount",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "sts:AssumeRole"
}
]
}
A2) Trust with ExternalId
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAssumeWithExternalId",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/competitor-runner" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "challenge-external-id" }
}
}
]
}
A3) Deny AssumeRole unless MFA present
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAssumeWithoutMfa",
"Effect": "Deny",
"Principal": "*",
"Action": "sts:AssumeRole",
"Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } }
}
]
}
B) S3 bucket policy blocks
B1) Enforce TLS (deny non-HTTPS)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::BUCKET", "arn:aws:s3:::BUCKET/*"],
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
}
]
}
B2) Restrict to a VPC endpoint (gateway endpoint)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyViaVpce",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::BUCKET", "arn:aws:s3:::BUCKET/*"],
"Condition": { "StringNotEquals": { "aws:sourceVpce": "vpce-xxxxxxxx" } }
}
]
}
B3) Require SSE-KMS on PutObject
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET/*",
"Condition": {
"StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
}
}
]
}
C) SNS topic policy blocks
C1) Allow S3 to publish to SNS (with SourceArn + SourceAccount)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3Publish",
"Effect": "Allow",
"Principal": { "Service": "s3.amazonaws.com" },
"Action": "sns:Publish",
"Resource": "arn:aws:sns:REGION:ACCOUNT_ID:TOPIC",
"Condition": {
"StringEquals": { "aws:SourceAccount": "ACCOUNT_ID" },
"ArnLike": { "aws:SourceArn": "arn:aws:s3:::BUCKET" }
}
}
]
}
D) SQS queue policy blocks
D1) Allow receive/delete for a role
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowConsumerRole",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:role/consumer-role" },
"Action": [
"sqs:GetQueueUrl",
"sqs:GetQueueAttributes",
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:ChangeMessageVisibility"
],
"Resource": "arn:aws:sqs:REGION:ACCOUNT_ID:QUEUE"
}
]
}
D2) Require TLS for SQS (deny non-HTTPS)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "sqs:*",
"Resource": "arn:aws:sqs:REGION:ACCOUNT_ID:QUEUE",
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
}
]
}
E) KMS key policy blocks
E1) Allow an IAM role to use the key
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowRoleUseKey",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:role/app-role" },
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
]
}
E2) Allow CreateGrant for AWS resources
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGrantForAwsResource",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:role/app-role" },
"Action": ["kms:CreateGrant", "kms:ListGrants", "kms:RevokeGrant"],
"Resource": "*",
"Condition": { "Bool": { "kms:GrantIsForAWSResource": "true" } }
}
]
}
F) Permissions boundary patterns
F1) Allow role creation only when boundary is attached
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCreateRoleWithBoundaryOnly",
"Effect": "Allow",
"Action": ["iam:CreateRole", "iam:PutRolePermissionsBoundary"],
"Resource": "*",
"Condition": {
"StringEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::ACCOUNT_ID:policy/BoundaryPolicy"
}
}
}
]
}
G) SCP blocks (Org guardrails)
G1) Deny disabling CloudTrail
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDisableCloudTrail",
"Effect": "Deny",
"Action": ["cloudtrail:StopLogging", "cloudtrail:DeleteTrail", "cloudtrail:UpdateTrail"],
"Resource": "*"
}
]
}
G2) Deny S3 public ACLs
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyPublicAcls",
"Effect": "Deny",
"Action": ["s3:PutBucketAcl", "s3:PutObjectAcl"],
"Resource": "*",
"Condition": {
"StringEquals": { "s3:x-amz-acl": ["public-read", "public-read-write", "authenticated-read"] }
}
}
]
}
Rapid triage checklist
- Confirm identity:
aws sts get-caller-identity - Check explicit Deny (IAM, bucket/queue/topic policy, SCP, permission boundary)
- If AssumeRole: trust policy principal + conditions (ExternalId/MFA/OIDC)
- If resource access: resource policy + KMS key policy (if encrypted)
- If in VPC: endpoint policy + DNS + SG/NACL return traffic
- Validate by simulating: IAM Policy Simulator (when available)