どうも、ちゃだいん(@chazuke4649)です。
Account Factory for Terraform (AFT) は、AWS Control Tower を拡張し、Terraformコードで定義したアカウントベースライン設定の配布を自動化できる強力なカスタマイズソリューションです。
AFTによってAWSアカウントのカスタマイズを行う際、いきなりパイプラインに乗せて対象のAWSアカウントに配布するのではなく、事前に ローカル環境からterraform plan
やterraform validate
などで検証したい場合があります。それ以外でも何かしらローカルから試したいこと・やりたいことは出てきます。
このニーズに対して、実はしれっと公式ドキュメントの AWS Prescriptive Guidance にて紹介されていたので、実際にやってみます。
概要
今回は、AFTの「アカウントカスタマイズ」を利用し、既存のAWSアカウント sandbox
へのカスタマイズを、あらかじめローカル環境からテスト(terraoform plan)します。
前提
- ローカル環境: MacBook Pro
- MacOS: 13.4.1
- AFT構成パターン: GitHub x Terraform OSS
- AFT version: 1.9.2
- AWS Control Tower 環境と AFT モジュールはデプロイ済み、過去にカスタマイズ実績有り
- その他、ドキュメントの「前提条件と制限事項」も参照ください
手順
基本的に先述の公式ドキュメントを参考にしています。
- リモートリポジトリをローカルにクローンする
- シェルスクリプトをローカルに保存する
- backend.tfとaft-providers.tfを作成する
- AFT管理アカウントの認証情報を試す
- シェルスクリプトを使ってinitする
- シェルスクリプトを使ってplanする
- .gitignoreを作成し、プッシュする
0. リモートリポジトリをローカルにクローンする
ローカル検証したいリモートのAFTリポジトリ(※今回は「アカウントカスタマイズ」)をクローンします。
自分の環境ではすでにクローン済みのため割愛します。
1. シェルスクリプトをローカルに保存する
ローカルのどこかか適切なディレクトリにドキュメントに記載されているシェルスクリプト ct_terraform.sh
をローカル保存しておきます。
(参考までに以下にも転記しますが、実際はオリジナルを流用ください)
ct_terraform.sh
#! /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 "$@"
2. backend.tfとaft-providers.tfを作成する
AFTパイプラインでTerrformが実行される際、CodeBuild内にてbackend.tfとaft-providers.tfが生成・利用されます。 これをローカル環境にコピペし利用すれば、AFTパイプライン内で実行するのと同等のstateファイルの参照やプロバイダー設定を利用できる格好となります。
AFT管理アカウントのマネジメントコンソールにログインし、CodePipelineコンソールを開きます。
パイプラインの一覧の中から、対象のAWSアカウントIDが含まれたパイプラインを選択します。
今回は、「グローバルカスタマイズ」ではなく「アカウントカスタマイズ」なので、アカウントカスタマイズのCodeBuildのログを開きます。
aft-providers.tf
で検索すると 該当箇所がヒットしたので、こちらをローカルにコピペします。
backend.tf
も同様です。
ディレクトリ構造を見ておくと、account-customizations
以下をクローンしたとして、今回は、アカウント単位でディレクトリを切っており、sandbox
を作っています。その配下の terraform
配下に、全て必要なファイルを格納しています。
% pwd
/Users/chadain/Project/account-customizations/sandbox/terraform
% tree -a -L 1
.
├── .gitignore
├── .terraform
├── .terraform.lock.hcl
├── aft-providers.jinja
├── aft-providers.tf
├── backend.jinja
├── backend.tf
└── s3.tf
- 冒頭のシェルスクリプトは、ここに入れてません
- 元々、「アカウントカスタマイズ」のアカウント単位でコピペするテンプレートの中には、
*.jinja
ファイルしか入ってません
3. AFT管理アカウントの認証情報を試す
IAM Identiy Center を利用している場合は、Identity Centerユーザーポータルから、AFT管理アカウントへの管理者ユーザーなどの一時的クレデンシャルをコピーし、ターミナルの環境変数へセットします。
AFTのホームリージョンが東京である場合、AWS CLI側でも東京リージョンが設定されていることを確認します。
4. シェルスクリプトを使ってinitする
先ほどローカル保存したシェルスクリプトを呼び出して、terraform init
を実行します。
% ../shellscript/ct_terraform.sh init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.23.1...
- Installed hashicorp/aws v5.23.1 (signed by HashiCorp)
Terraform has been successfully initialized!
問題なく、CodeBuild上のバックエンドとプロバイダー設定と、シェルスクリプトによるAFT系IAMロールの一時クレデンシャルを利用して、initすることができました。
5. シェルスクリプトを使ってplanする
ここでは、元々カスタマイズしていたS3にPublic Access Block設定を追加してみます。(ハイライト行)
s3.tf
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "sandbox" {
bucket = "aft-sandbox-${data.aws_caller_identity.current.account_id}"
tags = { AccountId = "aft-sandbox-${data.aws_caller_identity.current.account_id}" }
}
resource "aws_s3_bucket_versioning" "sandbox" {
bucket = aws_s3_bucket.sandbox.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_public_access_block" "sandbox" {
bucket = aws_s3_bucket.sandbox.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
シェルスクリプトを呼び出して、terraform plan
を実行します。
% ../shellscript/ct_terraform.sh plan
## 中略
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket_public_access_block.sandbox will be created
+ resource "aws_s3_bucket_public_access_block" "sandbox" {
+ block_public_acls = true
+ block_public_policy = true
+ bucket = "aft-sandbox-111111111111"
+ id = (known after apply)
+ ignore_public_acls = true
+ restrict_public_buckets = true
}
Plan: 1 to add, 0 to change, 0 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
問題なく追加できそうです。
これによって本検証の目的である、terraform planなどのコマンドをローカルから実行することができました。
6. .gitignoreを作成し、プッシュする
ローカルから実行するためにコピペしたaft-providers.tf
やbackend.tf
、terraform init で生成された .terraform/* や
.terraform.lock.hcl` はリモートリポジトリ側では不要なので、.gitignoreに登録します。
そして、S3.tfの変更をリモートリポジトリにプッシュします。
% echo aft-providers.tf >> .gitignore
% echo backend.tf >> .gitignore
% echo .terraform.lock.hcl >> .gitignore
% git add -A
% git commit -m"S3にブロックパブリックアクセス設定を追加する"
% git push origin main
あとは、本来のフローに戻り、AFTパイプライン上で既存のAWSアカウントへのカスタマイズの実行を行い、正しくAFTパイプラインによりカスタマイズを反映させれば完了です。
AFTパイプラインの手動実行によりSandboxアカウントへカスタマイズを実行したところ、問題なく成功したことが確認できました。
余談
Terraform バージョンを合わせる方法
AFTパイプラインで使用しているTerrformバージョンと、ローカル環境のTeraformバージョンを合わせる必要があります。
AFT側は、パブリックモジュールのパラメータにて指定が可能です。
terraform_version | aws-ia/terraform-aws-control_tower_account_factory
終わりに
AFTパイプラインのカスタマイズをローカルから検証する方法を試しました。
それでは今日はこの辺で。ちゃだいん(@chazuke4649)でした。