Terraform with Localstack

Introduction

The idea for this post originated from the need to showcase some Terraform and the cherry on the cake is to test terraform to deploy the infra locally using localstack.

Why? Because I don’t want to create a personal AWS account for this and I want to give this a try.

Requirements

Installing aws-cli

Nothing better than following the official documentation, but on Linux just do:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    sudo ./aws/install

Configuring aws-cli

Again, from official documentation, we can create a custom profile to make it easy to interact with localstack. For this, we open the file ~/.aws/config and write:

[profile localstack]
region=us-east-1
output=json
endpoint_url = http://localhost:4566

The same way, we now open the file ~/.aws/credentials and write:

[localstack]
aws_access_key_id=test
aws_secret_access_key=test

Localstack

For this, I will just launch localstack on a docker container. A simple search online will get you a docker-compose.yml from the official github repository.

We don’t need all the things on that docker-compose.yml, so we can work with a simplified version:

version: "3.8"

services:
  localstack:
    image: localstack/localstack
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range

In this case, we are going to use the latest version of the localstack docker image and will be exposing the necessary ports to interact with it. So now we can start the container and run a test:

docker-compose up -d && \
    aws --profile localstack s3 mb s3://test && \
    aws --profile localstack s3 ls

And the output should be something like:

2025-03-03 22:19:31 test

which mean that we were able to create an S3 bucket on the localstack instance.

Terraform

Now, for installing terraform I’d strongly recommend to go with asdf-vm. But, for the sake of this post I’ll just get the binary from offical sources:

curl -O https://releases.hashicorp.com/terraform/1.11.0/terraform_1.11.0_linux_amd64.zip && \
    unzip terraform_1.11.0_linux_amd64.zip && \
    mv terraform ~/.local/bin/.

Here, I am assuming that ~/.local/bin is in your $PATH but in case it is not, put this in your ~/.bashrc or ~/.zshrc or the one for the shell you are using:

export PATH=$HOME/.local/bin:$PATH

and then source the file source ~/.bashrc.

Terraform configuration

Once again, following the official documentation (on the manual configuration), we should create our test.tf file and write:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.27"
    }
  }
  required_version = ">= 1.10.0"
}

provider "aws" {
  profile                     = "localstack"
  region                      = "us-east-1"

  s3_use_path_style           = true
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    s3             = "http://s3.localhost.localstack.cloud:4566"
  }
}

The only difference with the official doc, is that we are defining the required_providers versions and the terraform version, because it is always a good practice. Also, we are using the aws profile we created previously localstack, instead of writing the access_key and secret_key.

Deploying an S3 Bucket

Because this is a test, lets just put everything together in the same test.tf file and now we create a ressource (s3 bucket) by adding at the end of the file:

resource "aws_s3_bucket" "albx" {
  bucket = "albx-test-bucket"
}

Now we initialize the provider and the used modules with terraform init, followed by a terraform plan to see what terraform is going to be doing and because everything should look just fine in this case, we go ahead and apply with terraform apply.

After this, we should be able to see our newly created s3 bucket by checking with the aws-cli:

aws s3 ls --profile localstack

and the output should look like:

2025-03-03 22:19:31 test
2025-03-03 23:03:31 albx-test-bucket

That’s it; we should be able to configure the rest of the endpoints (you’ll find them in the official documentation) for the aws provider, and with that we could just play by deploying more complex architectures on localstack before going to an actual AWS account.