Terraform Workspaces for Local AWS Development

There are times when you need to develop the AWS API but could get away with merely imitating it. Using containers, we can stand up emulated AWS services. This can help when say… you’re completely disconnected or just want to save money while developing. But how do you continue with your typical IaC workflow? Terraform allows you to override the AWS API URLs by explicitly setting local endpoints. In this post, I’ll show you how to use containers and Terraform workspaces to develop the AWS API 100% locally!

Define AWS Provider

We will initialize the provider block with our region configuration in our terraform directory. Then with the use of dynamic blocks, we can set individual endpoints. In this case, we want to configure the DynamoDB endpoint. If using localstack, you can expand this to a larger array of services.

provider "aws" {
  region = "us-east-2"

  dynamic "endpoints" {
    for_each = terraform.workspace == "local" ? [1] : []
    content {
      dynamodb = "http://localhost:8000"
    }
  }
}

Create Dynamo Resource

resource "aws_dynamodb_table" "workspaces" {
  name           = "workspaces"
  billing_mode   = "PROVISIONED"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "id"

  attribute {
    name = "id"
    type = "S"
  }
}

Start dynamo docker container

 docker run --rm -d -p 8000:8000 amazon/dynamodb-local

Create and Select Workspace

If this is the first time, you will want to create the local workspace:

terraform workspace new local

Otherwise, if switching between local and the default workspace

terraform workspace select local

Run Terraform Apply

~ terraform apply                
...
aws_dynamodb_table.workspaces: Creating...
aws_dynamodb_table.workspaces: Creation complete after 0s [id=workspaces]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Now we can validate the table exists locally and not in AWS

### Remote
~  aws dynamodb list-tables
{
    "TableNames": []
}
### Local
~ aws dynamodb list-tables --endpoint http://localhost:8000
{
    "TableNames": [
        "workspaces"
    ]
}

Provision in AWS

To provision the resource now in AWS you can switch back to the default namespace, and run terraform apply again.

~ terraform workspace select default
~ terraform apply -auto-approve                                   
...
aws_dynamodb_table.workspaces: Creating...
aws_dynamodb_table.workspaces: Still creating... [10s elapsed]
aws_dynamodb_table.workspaces: Creation complete after 13s [id=workspaces]
~ aws dynamodb list-tables
{
    "TableNames": [
        "workspaces"
    ]
}