Skip to content

IAM Policy Examples

Five policy shapes that cover most of what an identity-based policy is asked to do. All use the reserved documentation address ranges and account ID 123456789012.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
]
}
]
}

Both ARNs are needed: bucket-level actions such as s3:ListBucket act on the bucket, object-level actions such as s3:GetObject act on the objects. "Resource": "*" would work but grants the same access to every bucket in the account.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}

Note that aws:MultiFactorAuthPresent is absent — rather than false — for requests made with long-term credentials such as an access key. A Bool true condition therefore fails closed for those, which is the intended behaviour here. Writing the inverse as an explicit Deny with Bool: false does not achieve the same thing, because the key is missing rather than false.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"cloudfront:*",
"route53:*",
"support:*",
"sts:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["eu-west-1", "eu-west-2"]
}
}
}
]
}

The NotAction exclusions are required. Several AWS services are global with endpoints in us-east-1; denying every action outside the approved Regions without excluding them breaks IAM, Organizations, CloudFront, Route 53, STS and Support.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ec2:StartInstances", "ec2:StopInstances"],
"Resource": "arn:aws:ec2:*:123456789012:instance/*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "Production"
}
}
}
]
}

Attribute-based access control in its simplest form: the permission follows the tag, so a new instance is covered the moment it is tagged. It depends on tagging being enforced — pair it with an SCP or a Config rule that requires the tag at creation.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["192.0.2.0/24", "203.0.113.0/24"]
},
"Bool": {
"aws:ViaAWSService": "false"
}
}
}
]
}

Written as a Deny so it cannot be overridden by another allow. The aws:ViaAWSService condition is what stops it breaking calls that an AWS service makes on the principal’s behalf, which do not originate from the office address range.