ACL (Access Control List) in S3 is a mechanism for defining permissions (read, write, full control) on objects and buckets, allowing you to grant access to specific AWS accounts or groups.
Key takeaways:
Terraform as IaC tool: Terraform is a powerful infrastructure as code (IaC) tool that allows us to define and provision infrastructure using code in a safe, consistent, and efficient manner.
S3 bucket creation: Create an S3 bucket using Terraform by defining AWS credentials and specifying bucket properties such as region, public access settings, ownership controls, and ACL permissions.
Public access: Manage ownership controls and public access policies for S3 buckets.
Uploading objects to S3: Terraform also helps with uploading files.
Terraform is a software tool for infrastructure as code (IaC), a technique for provisioning computing infrastructure using machine-readable code files. Terraform is used for building, editing, and versioning infrastructure safely and efficiently. It efficiently manages the provisioning of infrastructure and does not ask how to provision the infrastructure; it just asks what to do and implement it.
First, we’ll investigate the code and then provision the infrastructure. Finally, let’s examine how to create a public S3 bucket. Then, we’ll upload an object to the bucket and finally attach a resource policy to publicly access the bucket objects.
Follow the “What does Infrastructure as Code even mean?” Answer to learn further about IaC.
We need to log into AWS using the provider block. The credentials access_key
and the secret_key
are used to log in to AWS. These credentials should be passed as environment variables to Terraform, but here, we’ll pass them in the file for learning purposes. To create an S3 bucket with public contents, we’ll specify ownership controls and allow public access to the bucket and bucket ACL permissions using resource blocks.
provider "aws"{region="us-east-1"# Do not pass access and secret access key in a file, this is for learning purposes only# Pass these values through CMD or in encrypted format.access_key = "{{access_key_id}}"secret_key = "{{secret_access_key}}"}resource "aws_s3_bucket" "my_bucket"{bucket="my-bucket-<Unique_Number/Text_Here>"}resource "aws_s3_bucket_ownership_controls" "my_bucket" {bucket = aws_s3_bucket.my_bucket.idrule {object_ownership = "BucketOwnerPreferred"}}resource "aws_s3_bucket_public_access_block" "my_bucket" {bucket = aws_s3_bucket.my_bucket.idblock_public_acls = falseblock_public_policy = falseignore_public_acls = truerestrict_public_buckets = false}resource "aws_s3_bucket_acl" "my_bucket" {depends_on = [aws_s3_bucket_ownership_controls.my_bucket,aws_s3_bucket_public_access_block.my_bucket,]bucket = aws_s3_bucket.my_bucket.idacl = "public-read"}
Let’s take a look at the code above line by line and understand it carefully.
Lines 1–7: A provider block is used to specify that the Terraform configuration will be using AWS as the provider. It also sets the AWS region to us-east-1
and provides the AWS access key and secret key for authentication.
Lines 8–10: A resource block is used to create and name the S3 bucket.
Lines 12–17: This resource block configures ownership controls of the S3 bucket. It specifies that the object ownership is set to BucketOwnerPreferred
. This ensures that the bucket owner owns objects uploaded to the bucket.
Lines 19–26: This block configures public access settings for the S3 bucket. The bucket
attribute is used to reference the ID of the S3 bucket. Different attributes like block_public_acls
, block_public_policy
, etc., are set to false
, to allow public access.
Lines 28–36: This block sets the ACL for the S3 bucket to public-read.
The depends_on
attribute ensures that this resource depends on the completion of the ownership controls and public access block configurations.
Now that we have created a public S3 bucket on AWS. We'll upload an object index.html
to our S3 bucket.
resource "aws_s3_object" "my_object" {bucket = aws_s3_bucket.my_bucket.bucketkey = "index.html"source = "index.html"content_type="text/html"}
Let’s take a look at the above resource block and understand it carefully.
Lines 1–6: The block uploads a file index.html
to the S3 bucket my_bucket
with the specified key. The source
attribute specifies the local file to upload. The key
attribute specifies the key (path) of the S3 object.
We have created a public S3 bucket and uploaded index.html
to it. To allow public access to the bucket’s contents, we would attach a resource policy. We'll attach a resource policy to the bucket using a data block.
data "aws_iam_policy_document" "allow_access" {statement {principals {type = "*"identifiers = ["*"]}actions = ["s3:GetObject"]resources = [aws_s3_bucket.my_bucket.arn,"${aws_s3_bucket.my_bucket.arn}/*",]}}resource "aws_s3_bucket_policy" "allow_access" {bucket = aws_s3_bucket.my_bucket.idpolicy = data.aws_iam_policy_document.allow_access.json}
Let’s take a look at the above resource blocks and understand it carefully.
Lines 1–17: This block creates an IAM policy document to allow public access to objects in the S3 bucket using a data block. The policy allows the s3:GetObject
permission to everyone (*
) for the specified S3 bucket and its objects.
Lines 19–22: This block attaches the IAM policy document, allow_access
, from the data block to the S3 bucket as a bucket policy. The bucket
attribute references the S3 bucket created earlier, and the policy
attribute references the JSON representation of the IAM policy document.
Now that we have understood the code, let’s combine all the code blocks and provision the infrastructure on AWS.
Note: Replace the placeholder
<Unique_Number/Text_Here>
with a unique number or text at the end of the S3 bucket name on line 5 in the widget below to ensure that the bucket name is globally unique.
provider "aws"{ region="us-east-1" } resource "aws_s3_bucket" "my_bucket"{ bucket="my-bucket-<Unique_Number/Text_Here>" } resource "aws_s3_bucket_ownership_controls" "my_bucket" { bucket = aws_s3_bucket.my_bucket.id rule { object_ownership = "BucketOwnerPreferred" } } resource "aws_s3_bucket_public_access_block" "my_bucket" { bucket = aws_s3_bucket.my_bucket.id block_public_acls = false block_public_policy = false ignore_public_acls = true restrict_public_buckets = false } resource "aws_s3_bucket_acl" "my_bucket" { depends_on = [ aws_s3_bucket_ownership_controls.my_bucket, aws_s3_bucket_public_access_block.my_bucket, ] bucket = aws_s3_bucket.my_bucket.id acl = "public-read" } resource "aws_s3_object" "my_object" { bucket = aws_s3_bucket.my_bucket.bucket key = "index.html" source = "index.html" content_type="text/html" } data "aws_iam_policy_document" "allow_access" { statement { principals { type = "*" identifiers = ["*"] } actions = [ "s3:GetObject" ] resources = [ aws_s3_bucket.my_bucket.arn, "${aws_s3_bucket.my_bucket.arn}/*", ] } } resource "aws_s3_bucket_policy" "allow_access" { bucket = aws_s3_bucket.my_bucket.id policy = data.aws_iam_policy_document.allow_access.json }
Click the “Run” button and type the following command to initialize the Terraform directory, terraform init
is used to resolve and install dependencies. After initializing the directory, use terraform plan
to see the execution plan; it’s an optional step. After this, execute the configuration file using terraform apply
, it asks for confirmation, then type yes
, and then Terraform will create the requested infrastructure.
terraform initterraform apply
We have provisioned the infrastructure; let’s log in to our AWS account to verify the creation of the bucket. We can also check that we have uploaded index.html
to our S3 bucket; take a look at the contents of our S3 bucket to verify that the object is uploaded to the bucket.
Search and select S3 in the AWS Management Console.
Go to the S3 buckets page and click the bucket name to open the bucket.
We can see the uploaded file index.html
in the bucket.
To deepen your understanding of provisioning AWS resources using Terraform, consider checking out these comprehensive Cloud Labs:
We briefly discussed Terraform, how to provision an S3 bucket, and how to control bucket permissions. We also learned how to modify a bucket’s public permissions and uploaded an object using the Terraform configurations.
Haven’t found what you were looking for? Contact Us
Free Resources