Ian Norton

Website and blog

Follow me on GitHub

Terraforming your AWS parent account - bootstrapping

In the modern AWS world, it’s not uncommon to have multiple AWS accounts under a parent billing account for different environments such as dev, qa and production. Let’s look at how we get this started.

All of these steps are assuming Terraform v12.

Bootstrap

The following items are initial bootstrap and don’t rely on shared state or DynamoDB for locking. At this point we are assuming that the bootstrap steps are being followed by one person and nobody else will be working on the account at the same time.

IAM user and key

Before we can begin working with the account, we need to manually create an IAM user and key pair. Allocate the IAM user the policy arn:aws:iam::aws:policy/AdministratorAccess which will give us access to all resources for the next steps.

This may be your own user, but from here on in we assume that the credentials are in your AWS credentials file with the profile name parent.

S3 Bucket for state

If you’re in a shared environment with more than a single user (which is likely if you’re looking at creating multiple accounts) now is the time to create an S3 bucket for us to store shared state in.

module "shared_state" {
  source = "terraform-aws-modules/s3-bucket/aws"
  bucket = "shared-state"

  acl                     = "private"
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm     = "aws:kms"
      }
    }
  }

  versioning = {
    enabled = true
  }
}

At this point we are assuming the user account being used has admin rights so we’re not going to talk about permissions on the bucket. By specifying the sse_algorithm but not the kms_master_key_id we get the default AWS key aws/s3 is used which may not be the key you wish to use in production.

DynamoDB

Next we need a DynamoDB for tracking locks and making sure we don’t have multiple people working on the same things at the same times.

module "dynamodb_table" {
  source   = "terraform-aws-modules/dynamodb-table/aws"

  name     = "terraform-locks"
  hash_key = "LockID"

  read_capacity  = 20
  write_capacity = 20

  attributes = [
    {
      name = "LockID"
      type = "S"
    }
  ]
}

At this point we are assuming the user account being used has admin rights so we’re not going to talk about permissions on the DynamoDB.

See also