Write a least-privilege S3 read policy
📑 On this page
Part 104 of AWS from Zero. This lesson changes or inspects one IAM concept so the permission model stays understandable.
What we are learning
S3 bucket actions and object actions use different ARN shapes. Least privilege often needs separate statements.
Before you run it
BUCKET="replace-with-private-bucket"
PREFIX="shared/reports"Use a sandbox bucket and preserve the distinction between the bucket ARN and object ARNs.
The command
cat > s3-read-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::$BUCKET",
"Condition": {"StringLike": {"s3:prefix": ["$PREFIX", "$PREFIX/*"]}}
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::$BUCKET/$PREFIX/*"
}
]
}
EOFThe list condition narrows visible keys, while the object ARN narrows readable objects.
Inspect the result
aws accessanalyzer validate-policy \
--policy-type IDENTITY_POLICY \
--policy-document file://s3-read-policy.jsonRead the returned ARN, path, IDs, and attachment state instead of checking only the command exit code.
One tiny variation
aws iam create-policy \
--policy-name AwsZeroReportsRead \
--policy-document file://s3-read-policy.jsonCreate the managed policy only after validation and review.
Common mistake
Using only arn:aws:s3:::bucket/prefix/* does not cover s3:ListBucket, because that action targets the bucket resource itself.
Cleanup
rm s3-read-policy.jsonIf you created the managed policy variation, detach and delete it after testing.
Next, we will learn Understand IAM Action wildcards.