Setting up a new AWS account with Terraform

Bjorn Krolsavatar

Bjorn Krols

Published on
11 January 2022

Create AWS account

Create an AWS account.

Copy the access keys of your root user and add them to your .aws/credentials file.

Set up provider

terraform {
  required_version = "~> 1.0.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
  profile = "your-named-profile"
  region  = "eu-west-1"
}

Create state bucket

Use the AWS CLI to create an S3 bucket.

#!/bin/bash

export AWS_PROFILE=my-named-profile

BUCKET_NAME=terraform-state
BUCKET_REGION=eu-west-1

echo Creating bucket
aws s3 mb s3://$BUCKET_NAME --region "$BUCKET_REGION"

echo Enabling versioning
aws s3api put-bucket-versioning --bucket $BUCKET_NAME --versioning-configuration Status=Enabled

echo Enabling encryption
aws s3api put-bucket-encryption --bucket $BUCKET_NAME --server-side-encryption-configuration '{"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]}'

echo Making bucket private
aws s3api put-bucket-acl --bucket $BUCKET_NAME --acl private

Echo Finished

Update your backend to use the bucket.

terraform {
  backend "s3" {
    profile = "your-named-profile"
    region  = "eu-west-1"
    bucket  = "terraform-state"
    key     = "project-key"
  }
}

Choose account alias

If you want the URL for your sign-in page to contain your company name (or other friendly identifier) instead of your AWS account ID, you can create an account alias.

resource "aws_iam_account_alias" "alias" {
  account_alias = "my-account-alias"
}
# Example sign-in page for account alias
https://my-account-alias.signin.aws.amazon.com/console/

Create console users group

resource "aws_iam_group" "console_group" {
  name = "console"
}

Create admin group

resource "aws_iam_group" "admin_group" {
  name = "admins"
}

resource "aws_iam_group_policy_attachment" "admin_group_policy" {
  group      = aws_iam_group.admin_group.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

Set password policy

resource "aws_iam_account_password_policy" "password_policy" {
  minimum_password_length        = 8
  require_lowercase_characters   = true
  require_numbers                = true
  require_uppercase_characters   = true
  require_symbols                = true
  allow_users_to_change_password = true
}

Enforce MFA

data "aws_caller_identity" "current" {}
module "enforce_mfa" {
  source                          = "terraform-module/enforce-mfa/aws"
  version                         = "0.12.5"
  policy_name                     = "managed-mfa-enforce"
  account_id                      = data.aws_caller_identity.current.id
  groups                          = [aws_iam_group.console_group.name]
  manage_own_signing_certificates = true
  manage_own_ssh_public_keys      = true
  manage_own_git_credentials      = true
}

Create users

locals {
  users = [
    {
      name : "Bjorn",
      groups : [aws_iam_group.console_group.name, aws_iam_group.admin_group.name]
    },
    {
      name : "CI",
      groups : [aws_iam_group.admin_group.name]
    }
  ]
}

resource "aws_iam_user" "user" {
  for_each = { for user in local.users : user.name => user }
  name     = each.value.name
}

resource "aws_iam_user_group_membership" "user_group_membership" {
  for_each = { for user in local.users : user.name => user }
  user     = each.value.name
  groups   = each.value.groups
  depends_on = [
    aws_iam_user.user
  ]
}

I then enable console access and create access keys manually via the console. It is possible to do this with Terraform, but it's a bit of a hassle.

Don't forget to set up MFA.

Set up budget alerts

locals {
  budget_alert_emails = [
    "john@doe.com",
    "jane@doe.com"
  ]
}

resource "aws_budgets_budget" "daily_budget" {
  name              = "daily-budget"
  budget_type       = "COST"
  limit_amount      = "10.0"
  limit_unit        = "USD"
  time_period_start = "2021-01-01_00:00"
  time_period_end   = "2085-01-01_00:00"
  time_unit         = "DAILY"
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = local.budget_alert_emails
  }
}

resource "aws_budgets_budget" "monthly_budget" {
  name              = "monthly-budget"
  budget_type       = "COST"
  limit_amount      = "50.0"
  limit_unit        = "USD"
  time_period_end   = "2085-01-01_00:00"
  time_period_start = "2021-01-01_00:00"
  time_unit         = "MONTHLY"
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_email_addresses = local.budget_alert_emails
  }
}

Delete root access keys

Revoke the access keys of your root user.

Copy the access keys of your admin user and add them to your .aws/credentials file.

Subscribe to our newsletter

The latest news, articles, and resources, sent to your inbox weekly.

More like this