How to create a publicly available bucket on AWS using Terraform
Tags: aws, terraform, serverless, storage
Published: 2024-05-14 09:46:20

It's really common to create publicly accessible S3 bucket from the the management console, this time we want to create an S3 bucket, upload an object to it, and make it publicly accessible using Terraform. 

## Prerequisites

- You have an AWS account.

- You have AWS CLI installed on your computer, test by typing aws on your command line and see a reply telling you how to structure a command else follow this link to install AWS CLI Install or update to the latest version of the AWS CLI – [AWS Command Line Interface (amazon.com)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
 

## What is Terraform

Terraform is a service that lets you define infrastructure using code, offering a structured way to represent your desired states while benefiting from features like versioning, collaboration, and automation.

This code-centric approach makes infrastructure changes more reliable and easier to track.

Moreover, Terraform integrates seamlessly with AWS, providing comprehensive support for provisioning and managing a wide array of AWS resources.

## Why use Terraform

- **Infrastructure as Code (IaC)**

   Terraform allows you to define infrastructure configurations using code, providing a consistent, automated approach to managing resources. This makes it easier to apply best practices, track changes, and collaborate with others, reducing the risk of manual errors. 

- **Easy Deployment of Infrastructure**

   Terraform streamlines infrastructure deployment through a simple command-line interface. By defining your desired state in code, you can deploy new environments or make changes to existing ones with a few commands, making it efficient and straightforward. 

- **Recreate Infrastructure Consistently**

   Terraform’s code-based approach enables you to create identical infrastructure multiple times. This is useful for spinning up identical test, staging, or production environments, ensuring consistency across deployments. 

- **Error-Free Deployment Once Configured**
   Once you’ve properly defined your Terraform configuration, deploying infrastructure becomes more predictable and less prone to errors. Terraform’s declarative nature ensures that the desired state is achieved without unexpected behavior, making deployments reliable. 

- **Resource Dependencies and Orchestration**

   Terraform manages dependencies between infrastructure resources, ensuring that they are created, modified, or destroyed in the correct order. This built-in orchestration reduces the risk of misconfigurations and simplifies complex infrastructure setups, allowing you to focus on the overall design rather than manual sequencing. 

## Create an AWS IAM user
You need to create an AWS user that you can use to create or deploy AWS resources through the command line. 

- In the AWS Console, go to the “Services” menu and select “IAM” (Identity and Access Management). 

- Click on **Users** in the IAM dashboard, Click the **Add users** button to create a new IAM user.

- Provide a username for the new user. 
Select **Access key – Programmatic access** to create access keys for CLI access, 

- Click **Next: Permissions**.
Under **Set permissions**, choose **Attach policies directly**.

- In the search box, type **AmazonS3FullAccess** and select the **AmazonS3FullAccess** policy.

- Click **Next: Review**. 
After creating the user, you’ll be presented with the user’s access key ID and secret access key. 

- Download the CSV file or copy the keys and store them securely. These keys are essential for CLI access and cannot be retrieved after this step. 

- Click **Close**.

- Open a terminal and run the command aws configure. You should see a user input show up if you have the AWS CLI installed on your computer.

Enter the access key ID, secret access key, desired AWS region, and output format (e.g., JSON).


![Using your IAM user on AWS CLI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nhgw3gm62wjnkeglccil.png)

Test the setup by running a simple AWS CLI command, like aws s3 **ls**, to verify that the user has access to S3. 

- Ensure you have Terraform installed on your computer. Type **terraform version** to confirm this if You don’t have Terraform installed, then follow this link
https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli 

- Create your Terraform configuration file, here’s mine, and I will explain the file’s content below.

```
provider "aws" {
    region = "eu-west-2"
}

resource "aws_s3_bucket" "my_public_bucket" {
    bucket = "public-documents"
    tags = {
        Name = "public-documents"
    }
}

resource "aws_s3_object" "test_object" {
    bucket = aws_s3_bucket.my_public_bucket.id
    key = "test.txt"
    content = "Just a test file"
}

resource "aws_s3_bucket_ownership_controls" "public_access" {
  bucket = aws_s3_bucket.my_public_bucket.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

resource "aws_s3_bucket_public_access_block" "public_access" {
    bucket = aws_s3_bucket.my_public_bucket.id

    block_public_acls       = false
    block_public_policy     = false
    ignore_public_acls      = false
    restrict_public_buckets = false
}

resource "aws_s3_bucket_acl" "public-read" {
    depends_on = [
        aws_s3_bucket_ownership_controls.public_access,
        aws_s3_bucket_public_access_block.public_access,
    ]

    bucket = aws_s3_bucket.my_public_bucket.id
    acl    = "public-read"
}

resource "aws_s3_bucket_policy" "bucket_public_policy" {
    bucket = aws_s3_bucket.my_public_bucket.id
    policy = data.aws_iam_policy_document.public_bucket_policy_statement.json
}

data "aws_iam_policy_document" "public_bucket_policy_statement" {
  statement {
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["*"]  # Allowing public access
    }

    actions = [
      "s3:GetObject",
    ]

    resources = [
      "${aws_s3_bucket.my_public_bucket.arn}/*",  # Apply the policy to all objects in the bucket
    ]
  }
}
```

The provider block is a plugin that allows Terraform to interact with different service APIs, like AWS, Azure, or Google Cloud Platform. When you define a provider, you’re setting the context for Terraform to work with a specific cloud service. 

Aws as the provider specifies that the configuration is for interacting with Amazon Web Services (AWS) and you just simply set the region to eu-west-2. 

The resource block in Terraform defines the actual infrastructure elements that Terraform creates, manages, modifies, or deletes. This block contains the parameters and settings associated with the resource type, as specified in the Terraform documentation. A resource may have mandatory attributes that must be set, along with optional attributes that can be configured as needed. 

In this particular configuration file, there are five resources, each dependent on the others to achieve the desired outcome. These dependencies are crucial for ensuring proper orchestration and sequencing during deployment.

Although the resource has a name in the Terraform code to keep track of it, this name does not necessarily correspond to the name of the infrastructure component that Terraform creates on the cloud (AWS in this case).

Instead, it’s a unique identifier within the Terraform configuration to manage dependencies and relationships between resources. 

The data block allows you to retrieve or reference existing infrastructure or external information within your configuration.

This is useful when you need to work with resources that are not created by Terraform but are still part of your deployment process. 

Now you have your file, follow the commands below to start the creation and configuration of your infrastructure.

Execute **terraform init**
This command initializes your Terraform working directory, downloading provider plugins and preparing your workspace.

To view the proposed changes to your infrastructure, ensuring there are no errors in your configuration file relative to the provider’s specifications.

Execute **terraform plan**
This step gives you an overview of what Terraform will do, allowing you to confirm the expected actions before making any changes.
To deploy the specified infrastructure according to your configuration file.

Execute **terraform apply**.
This command carries out the plan, creating or updating your infrastructure as described in your Terraform configuration.
You should see the response Apply complete as shown in the screenshot below.


![Terraform apply successful response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5gxm2uo0iaoc7j7acuk.png)

Locate your S3 page in your AWS account, and confirm that the bucket has been created and an object was uploaded to it. 

Locate the public link of the object and confirm that you can download the object from any computer using the public URL.

![Access S3 dashboard to see your bucket as deployed on Terraform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uthrb66s2ga8qzv9eezq.png)

To remove this particular infrastructure you have created using Terraform, ensure you are in the right directory where the config file is present, run the command **terraform destroy** 

Below is the relevant Terraform documentation I used when writing this config file, it contains more details for setting AWS S3 resources using Terraform. 

aws_s3_bucket_policy | Resources | hashicorp/aws | Terraform | Terraform Registry 

aws_s3_bucket_acl | Resources | hashicorp/aws | Terraform | Terraform Registry 

[Terraform Registry S3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object

## Conclusion
We have successfully set up S3 bucket and made it public using Terraform, we did not need to use the AWS management console for anything except to confirm that the resources have been set up as required. 

Thanks for reading through to the end, Let me hear your comment.

Read the story from my blog
[DigitalSpeed](https://www.digitalspeed.online/all-articles/how-to-create-a-publicly-accessible-bucket-on-aws-using-terraform/)