Protecting data in AWS S3 often starts with the simplest rule: read-only means read-only. Yet so many deployments skip the rigor. With Infrastructure as Code (IaC), you can define and enforce a read-only role for your S3 storage without relying on manual clicks or risky default settings. This isn’t just neat—it’s the difference between a controlled environment and a security hole waiting to be found.
AWS S3 read-only roles are straightforward to describe in code, but the details matter. The Identity and Access Management (IAM) policy must lock down every write operation and allow only the specific read actions your workload needs. By using IaC tools like Terraform or AWS CloudFormation, you remove human error, track every permission change in version control, and deploy to multiple environments without drift.
A basic Terraform example for an S3 read-only role:
resource "aws_iam_role""s3_readonly_role"{
name = "s3-readonly-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_policy""s3_readonly_policy"{
name = "s3-readonly-policy"
description = "Read-only access to all S3 buckets"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment""attach_s3_readonly"{
role = aws_iam_role.s3_readonly_role.name
policy_arn = aws_iam_policy.s3_readonly_policy.arn
}
Here, every line defines the exact shape of allowed access. The policy grants s3:GetObject and s3:ListBucket but nothing else. There is no PutObject. No DeleteObject. No accidental write. The role is deterministic, reproducible, and portable across accounts or regions.