Validate Account Factory for Terraform (AFT) code locally - AWS Prescriptive Guidance

Validate Account Factory for Terraform (AFT) code locally

Created by Alexandru Pop (AWS) and Michal Gorniak (AWS)

Environment: Production

Technologies: Infrastructure; DevOps; Modernization; DevelopmentAndTesting

Workload: Open-source

AWS services: AWS Control Tower

Summary

This pattern shows how to locally test HashiCorp Terraform code that’s managed by AWS Control Tower Account Factory for Terraform (AFT). Terraform is an open-source infrastructure as code (IaC) tool that helps you use code to provision and manage cloud infrastructure and resources. AFT sets up a Terraform pipeline that helps you provision and customize multiple AWS accounts in AWS Control Tower.

During code development, it can be helpful to test your Terraform infrastructure as code (IaC) locally, outside of the AFT pipeline. This pattern shows how to do the following:

  • Retrieve a local copy of the Terraform code that’s stored in the AWS CodeCommit repositories in your AFT management account.

  • Simulate the AFT pipeline locally by using the retrieved code.

This procedure can also be used to run Terraform commands that aren’t part of the normal AFT pipeline. For example, you can use this method to run commands such as terraform validate, terraform plan, terraform destroy, and terraform import.

Prerequisites and limitations

Prerequisites 

Limitations 

  • This pattern doesn’t cover the deployment steps required for AWS Control Tower, AFT, or any specific Terraform modules.

  • The output that’s generated locally during this procedure isn’t saved in the AFT pipeline runtime logs.

Architecture

Target technology stack  

  • AFT infrastructure deployed within an AWS Control Tower deployment

  • Terraform

  • Git

  • AWS CLI version 2

Automation and scale

This pattern shows how to locally invoke Terraform code for AFT global account customizations in a single AFT-managed AWS account. After your Terraform code is validated, you can apply it to the remaining accounts in your multi-account environment. For more information, see Re-invoke customizations in the AWS Control Tower documentation.

You can also use a similar process to run AFT account customizations in a local terminal. To locally invoke Terraform code from AFT account customizations, clone the aft-account-customizations repository instead of aft-global-account-customizations repository from CodeCommit in your AFT management account.

Tools

AWS services

Other services

  • HashiCorp Terraform is an open-source infrastructure as code (IaC) tool that helps you use code to provision and manage cloud infrastructure and resources.

  • Git is an open-source, distributed version control system.

Code 

The following is an example bash script that can be used to locally run Terraform code that’s managed by AFT. To use the script, follow the instructions in the Epics section of this pattern.

#! /bin/bash # Version: 1.1 2022-06-24 Unsetting AWS_PROFILE since, when set, it interferes with script operation #          1.0 2022-02-02 Initial Version # # Purpose: For use with AFT: This script runs the local copy of TF code as if it were running within AFT pipeline. #        * Facilitates testing of what the AFT pipline will do #           * Provides the ability to run terraform with custom arguments (like 'plan' or 'move') which are currently not supported within the pipeline. # # © 2021 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. # This AWS Content is provided subject to the terms of the AWS Customer Agreement # available at http://aws.amazon.com/agreement or other written agreement between # Customer and either Amazon Web Services, Inc. or Amazon Web Services EMEA SARL or both. # # Note: Arguments to this script are passed directly to 'terraform' without parsing nor validation by this script. # # Prerequisites: #    1. local copy of ct GIT repositories #    2. local backend.tf and aft-providers.tf filled with data for the target account on which terraform is to be run #       Hint: The contents of above files can be obtain from the logs of a previous execution of the AFT pipeline for the target account. #    3. 'terraform' binary is available in local PATH #    4. Recommended: .gitignore file containing 'backend.tf', 'aft_providers.tf' so the local copy of these files are not pushed back to git readonly credentials=$(aws sts assume-role \     --role-arn arn:aws:iam::$(aws sts get-caller-identity --query "Account" --output text ):role/AWSAFTAdmin \     --role-session-name AWSAFT-Session \     --query Credentials ) unset AWS_PROFILE export AWS_ACCESS_KEY_ID=$(echo $credentials | jq -r '.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(echo $credentials | jq -r '.SecretAccessKey') export AWS_SESSION_TOKEN=$(echo $credentials | jq -r '.SessionToken') terraform "$@"

Epics

TaskDescriptionSkills required

Save the example code as a local file.

  1. Copy the example bash script that’s in the Code section of this pattern and paste it into a code editor.

  2. Name the file ct_terraform.sh. Then, save the file locally inside a dedicated folder, such as ~/scripts or ~/bin.

AWS administrator

Make the example code runnable.

Open a terminal window and authenticate into your AWS AFT management account by doing one of the following:

  • Use an existing AWS CLI profile that’s configured with the permissions required to access the AFT management account. To use the profile, you can run the following command:

export AWS_PROFILE=<aft account profile name>
  • If your organization uses SSO to access AWS, enter the credentials for your AFT management account on your organization’s SSO page.

Note: Your organization might also have a custom tool to provide authentication credentials to your AWS environment.

AWS administrator

Verify access to AFT management account in the correct AWS Region.

Important: Make sure that you use the same terminal session that you authenticated into your AFT management account with.

  1. Navigate to your AFT deployment’s AWS Region by running the following command:

    export AWS_REGION=<aft_region>
  2. Make sure that you’re in the correct account by doing the following:

    • Run the following command:

    aws code-commit list-repositories
    • Then, verify that the repositories listed in the output match the names of the repositories that are in your AFT management account.

AWS administrator

Create a new, local directory to store the AFT repository code.

In the same terminal session, run the following commands:

mkdir my_aft cd my_aft
AWS administrator

Clone the remote AFT repository code.

  1. In your local terminal, run the following command:

    git clone codecommit::$AWS_REGION://aft-global-customizations

    Note: For simplicity, this procedure and AFT use a main code branch only. To use code branching, you can enter code branching commands here as well. However, any applied changes from the non-main branch will be rolled back when AFT automation applies code from the main branch.

  2. Then, navigate into the cloned directory by running the following command:

    cd aft-global-customizations/terraform
AWS administrator
TaskDescriptionSkills required

Open a previously run AFT pipeline and copy the Terraform configuration files to a local folder.

Note: The backend.tf and aft-providers.tf configuration files that are created in this epic are needed for the AFT pipeline to run locally. These files are created automatically within the cloud-based AFT pipeline, but must be created manually for the pipeline to run locally. Running the AFT pipeline locally requires one set of files that represents running the pipeline within a single AWS account.

  1. Using your AWS Control Tower management account credentials, sign in to the AWS Management Console. Then open the AWS CodePipeline console. Make sure that you’re in the same AWS Region where you deployed AFT.

  2. In the left navigation pane, choose Pipelines.

  3. Choose ###########-customizations-pipeline. (The ############ is the AWS account ID that you’re using to run Terraform code locally).

  4. Make sure that Most Recent Execution Marked shows a Succeeded value. If it the value is different, you must re-invoke your customizations in the AFT pipeline. For more information, see Re-invoke customizations in the AWS Control Tower documentation.

  5. Choose the most recent runtime to bring up its details.

  6. In the Apply-AFT-Global-Customizations section, find the Apply-Terraform stage.

  7. Select the Details section of the Apply-Terraform stage.

  8. Find the runtime log for the Apply-Terraform stage.

  9. In the runtime log, look for the section that begins and ends with the following lines:  “\n\n aft-providers.tf … “\n \n backend.tf”  

  10. Copy the output between these two labels and save them as a local file named aft-providers.tf within the local Terraform folder (your terminal session’s current working directory).

    Example auto generated providers.tf statement

    ## Autogenerated providers.tf ## ## Updated on: 2022-05-31 16:27:45 ## provider "aws" { region = "us-east-2" assume_role { role_arn = "arn:aws:iam::############:role/AWSAFTExecution" } default_tags { tags = { managed_by = "AFT" } } }
  11. In the runtime log, look for the section that begins and ends with the following lines: “\n\n tf … “\n \n backup.tf”  

  12. Copy the output between these two labels and save them as a local file named tf within the local Terraform folder (your terminal session’s current working directory).

Example autogenerated backend.tf statement

## Autogenerated backend.tf ## ## Updated on: 2022-05-31 16:27:45 ## terraform { required_version = ">= 0.15.0" backend "s3" { region = "us-east-2" bucket = "aft-backend-############-primary-region" key = "############-aft-global-customizations/terraform.tfstate" dynamodb_table = "aft-backend-############" encrypt = "true" kms_key_id = "cbdc21d6-e04d-4c37-854f-51e199cfcb7c" kms_key_id = "########-####-####-####-############" role_arn = "arn:aws:iam::#############:role/AWSAFTExecution" } }

Note: The backend.tf and aft-providers.tf files are tied to a specific AWS account, AFT deployment, and folder. These files are also different, depending on if they’re in the aft-global-customizations repository and aft-account-customizations repository within the same AFT deployment. Make sure that you generate both files from the same runtime listing.

AWS administrator
TaskDescriptionSkills required

Implement the Terraform configuration changes that you want to validate.

  1. Navigate to the cloned aft-global-customizations repository by running the following command:

    cd aft-global-customizations/terraform

    Note: The files backend.tf and aft-providers.tf are in this directory. The directory also contains Terraform files from the aft-global-customizations repository.

  2. Incorporate the Terraform code changes that you want to test locally into the configuration files.

AWS administrator

Run the ct_terraform.sh script and review the output.

  1. Navigate to the local folder that contains the sh script.

  2. To validate your modified Terraform code, run the ct_terraform.sh script by running the following command:

    ~/scripts/ct_terraform.sh apply

    Note: you can run any Terraform command during this step. To see a complete list of Terraform commands, run the following command:

    terraform --help
  3. Review the command output. Then, debug the code changes locally before committing and pushing the changes back to the AFT repository.

Important: 

  • Any changes made locally and not pushed back to the remote repository are temporary and may be undone at any time by a running AFT pipeline automation.

  • AFT automation can run at any time, because it can be invoked by other users and AFT automation triggers.

  • AFT will always apply code from the main branch of the repository, undoing any uncommitted changes.

AWS administrator
TaskDescriptionSkills required

Add references to the backend.tf and aft-providers.tf files to a .gitignore file.

Add the backend.tf and aft-providers.tf files that you created to a .gitignore file by running the following commands:

echo backend.tf >> .gitignore echo aft-providers.tf >>.gitignore

Note: Moving the files to the .gitignore file ensures that they don’t get committed and pushed back to the remote AFT repository.

AWS administrator

Commit and push your code changes to the remote AFT repository.

  1. To add any new Terraform configuration files to the repository, run the following command:

    git add <filename>
  2. To commit your changes and push them to the remote AFT repository in AWS CodeCommit, run the following commands:

    git commit -a git push

Important: The code changes that you introduce by following this procedure up until this point are applied to one AWS account only.

AWS administrator
TaskDescriptionSkills required

Roll out the changes to all of your accounts managed by AFT.

To roll out the changes to multiple AWS accounts managed by AFT, follow the instructions in Re-invoke customizations in the AWS Control Tower documentation.

AWS administrator