Overview
Goal:
You’ll use Terraform to create and manage AWS resources locally via LocalStack — no AWS account, no internet dependency, no billing.
You’ll:
-
Install and run LocalStack
-
Configure Terraform to use it
-
Create an S3 bucket, DynamoDB table, and Lambda function
-
Verify all with the AWS CLI
1. Prerequisites
Make sure you have the following installed:
| Tool | Check Command | Notes |
|---|---|---|
| Docker | docker --version | Required to run LocalStack |
| LocalStack CLI | localstack --version | Install: pip install localstack |
| AWS CLI | aws --version | For verifying resources |
| Terraform | terraform -v | Install from terraform.io/downloads |
| Python 3 (optional) | python3 --version | Used for Lambda function example |
2. Start LocalStack
Run this command:
localstack startYou should see logs like:
LocalStack version: 3.x.x
Ready.
By default, all emulated AWS services are accessible via:
http://localhost:4566
3. Configure AWS CLI for LocalStack
Run:
aws configureUse dummy values:
AWS Access Key ID [None]: test
AWS Secret Access Key [None]: test
Default region name [None]: us-east-1
Default output format [None]: json
Test it:
aws --endpoint-url=http://localhost:4566 s3 lsYou should get no error (empty list is fine).
4. Create Terraform Project
Make a folder:
mkdir terraform-localstack
cd terraform-localstack5. Create Terraform Configuration (main.tf)
Paste the following complete, working configuration:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
access_key = "test"
secret_key = "test"
region = "us-east-1"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
s3_use_path_style = true
# Use LocalStack endpoint
endpoints {
s3 = "http://localhost:4566"
dynamodb = "http://localhost:4566"
lambda = "http://localhost:4566"
iam = "http://localhost:4566"
sts = "http://localhost:4566"
}
default_tags {
tags = {
Environment = "localstack"
}
}
}
# 1 S3 Bucket
resource "aws_s3_bucket" "bucket" {
bucket = "my-localstack-bucket"
force_destroy = true
}
# 2 DynamoDB Table
resource "aws_dynamodb_table" "table" {
name = "MyLocalTable"
billing_mode = "PAY_PER_REQUEST"
hash_key = "ID"
attribute {
name = "ID"
type = "S"
}
}
# 3 Lambda Function
resource "aws_iam_role" "lambda_role" {
name = "lambda_exec_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Principal = { Service = "lambda.amazonaws.com" },
Effect = "Allow",
Sid = ""
}
]
})
}
resource "aws_lambda_function" "lambda" {
function_name = "MyLocalLambda"
filename = "lambda_function.zip"
handler = "lambda_function.lambda_handler"
runtime = "python3.9"
role = aws_iam_role.lambda_role.arn
source_code_hash = filebase64sha256("lambda_function.zip")
}6. Create the Lambda Code
Create a file named lambda_function.py:
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': 'Hello from LocalStack Lambda!'
}Zip it:
zip lambda.zip lambda_function.py7. Deploy via Terraform
Initialize and apply:
terraform init
terraform plan
terraform apply -auto-approveYou should see:
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
8. Verify Resources in LocalStack
List S3 buckets:
aws --endpoint-url=http://localhost:4566 s3 lsList DynamoDB tables:
aws --endpoint-url=http://localhost:4566 dynamodb list-tablesList Lambda functions:
aws --endpoint-url=http://localhost:4566 lambda list-functionsInvoke the Lambda:
aws --endpoint-url=http://localhost:4566 lambda invoke \
--function-name MyLocalLambda \
output.txt
cat output.txtExpected output:
{"statusCode": 200, "body": "Hello from LocalStack Lambda!"}
9. Destroy the Infrastructure
When done testing:
terraform destroy -auto-approve10. Troubleshooting Tips
| Issue | Cause | Fix |
|---|---|---|
lookup my-bucket.localhost DNS error | SDK using virtual-host–style URLs | Always use localstack start (not plain Docker run) or set AWS_S3_USE_PATH_STYLE=true |
| Terraform can’t connect | LocalStack not running | Check with localstack status services |
| Lambda fails | Missing lambda.zip | Ensure zipped code is in the same directory |
You’ve now created an entire AWS-like environment locally — S3, DynamoDB, Lambda — all controlled by Terraform and powered by LocalStack.