AWS Account settings with Terraform and terragrunt

I’m going to use Terraform (TF) plus Terragrunt (TG) to apply the various AWS account settings as code. Writing these settings as code assures me I can make the code change once and apply to all my environments or AWS accounts with the same settings, as Terragrunt calls it DRY. It stands for “Don’t Repeat Yourself”. Write once and apply on hundreds of AWS accounts!

If you haven’t installed Terraform and Terragrunt, go back a step by going through this first https://cloudly.engineer/2020/setup-infrastructure-as-code-environment/aws/ and maybe this https://cloudly.engineer/2019/aws-cloud-account-initial-configuration/aws/

Terraform code: Define resources

First account configuration is setting the account alias with the Terraform aws_iam_account_alias resource. This “settings” is an single git project.

resource "aws_iam_account_alias" "this" {
  account_alias = "acct-nickname-here"
}

Let’s break down this small piece of code.

  1. resource (no quotes) is a reserved keyword; means create or to ensure this type of resource exists
  2. aws_iam_account_alias” (double quotes with underscores) is the type of a resource you want to create. Here’s a list of them available today.Terraform attempts to always be up to date but it could be missing resource types or some features of a resource. Most of the time, it has all the core resource types and options available.
  3. this (double quotes with underscores) The last part of the first line is a name you want to give this resource for Terraform’s state file. My best practice is to always use “this” unless you have multiple of the same resource then be specific but don’t put the resource type in this name. That’s redundant nonsense.
  4. Within the braces it’s always one or more options with different types

    If you want to learn more Terraform click here.

Push this code up to your dev branch. We want to make sure it works before merging it to master.

Terragrunt Code: Deploy Resources

Terraform code just defines our infrastructure as code, Terragrunt with help of Terraform will do the actual deployment. The combination of these two will prevent us from repeating our code for however many AWS accounts we have. Below is my Terragrunt project for “settings”.

└── settings
    ├── README.md
    ├── dev
    │   └── terragrunt.hcl
        └── inputs.yml
        └── vars.tf
    ├── qa
    │   └── terragrunt.hcl
        └── inputs.yml
        └── vars.tf
    ├── sec
    │   └── terragrunt.hcl
        └── inputs.yml
        └── vars.tf
    ├── prod
    │   └── terragrunt.hcl
        └── inputs.yml
        └── vars.tf
    └── terragrunt.hcl
    └── inputs.yml
    └── vars.tf

terragrunt.hcl The root terragrunt.hcl and environment terragrunt.hcl files are a must
inputs.yml This yml file will contain variables specific to that environment, such as AWS CLI profile name
vars.tf Terraform files for each environment and one common vars.tf for all deployments

This separation of projects allows each environments to have different Terraform versions of your code at the same time. Let’s continue to see what I mean.

Main ‘terragrunt.hcl’

remote_state {
  backend = "s3"
  config = {
    bucket  = "bucket-name-for-terraform-state"
    key     = "${path_relative_to_include()}/terraform.tfstate"
    region  = local.local_inputs.aws_region,
    profile = local.local_inputs.aws_cli_profile
    encrypt = true
  }
}

locals {
  local_inputs  = yamldecode(file("${get_terragrunt_dir()}/inputs.yml"))
  global_inputs = yamldecode(file("${get_terragrunt_dir()}/inputs.yml"))
}

inputs = merge(local.global_inputs, local.local_inputs)

remote state
I’ll be storing the Terraform state file in Amazon S3.

  1. key All of my environments/accounts Terraform state files will be stored in one AWS S3 bucket separated by environments using the directory names. The Terragrunt function path_relative_to_include() is going to help with that.
  2. profile Since we’ll have several AWS accounts and profiles, this value will be dynamic and passed in from the environments input file.
  3. I think the rest are obvious.

locals

  1. local_inputs During Terraform plan or apply it grabs the variables for the environment to create Terraform files for that specific environment in the .terragrunt directory
  2. global_inputs contains variables that are common for all environments (if needed)

dev ‘terragrunt.hcl’

include {
  path = find_in_parent_folders()
}

terraform {
  source = "git@giturl.com:path/to/tf-modules/settings.git?ref=dev"
}

This says ‘hey go fetch the TF code from this URL but only the dev branch’. Also says ‘The Terraform backend configuration is in the main terragrunt.hcl file’. Next let’s init Terragrunt. If you haven’t already created the S3 bucket for your state file it will request to create.

I’ll be using aws cli profiles, this assumes you have already set this up
AWS Permissions Required

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowS3ForTerraform",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketVersioning",
                "s3:CreateBucket"
            ],
            "Resource": "arn:aws:s3:::YOUR-TF-BUCKET-NAME-HERE"
        },
        {
            "Sid": "AllowDownloadNUploadtoPrefix",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::YOUR-TF-BUCKET-NAME-HERE/*"
        }
    ]
}

dev ‘inputs.yml’

aws_cli_profile: "your-env-aws-cli-profile-name"
aws_region: "us-east-1"

dev ‘vars.tf’

variable aws_account_alias {
  default = "acct-nickname-here"
}

variable aws_region {}

variable aws_cli_profile {}

As said before, this is environment specific values. Let’s initiate already!

cd settings/dev/
terragrunt init
Output

----------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_iam_account_alias.this will be created
  + resource "aws_iam_account_alias" "this" {
      + account_alias = "acct-nickname-here"
      + id            = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

---------------------------------------------------------------------

Then ‘terragrunt apply’. Apply the configuration and verify in AWS IAM link.

IAM Sign in url

Going forward you can use this somewhat easy AWS sign in link for AWS commercial console sign in.

Terragrunt cache

Don’t put terragrunt cache in git. Add the following to your .gitignore file for your Terragrunt repositories.

*.terraform*
*.terragrunt*

If you update your Terraform you’ll have to update your Terragrunt too. You can do that with this additional argument

terragrunt init --terragrunt-source-update

This is the end of part 1. Subscribe for part 2!

As always if you see any errors, mistakes, have suggestions or questions please comment below. Don’t forget to like, share, and subscribe for more!

TOP 13 CLOUD ENGINEER POSITION INTERVIEW QUESTIONS AND ANSWERSBe prepared for you interview!
Posted in Aws

Published by

One thought on “AWS Account settings with Terraform and terragrunt

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.