Terraformによる環境開発をAWS Codeシリーズで統制する
投稿日: 2024/01/31
はじめに
こんにちは、佐藤です。
インフラコード化(IaC)を実装するツールの代表格としてTerraformやCloudformationなどが挙げられます。特にTerraformは特定の製品やサービスだけでなく、幅広い製品/サービスに対応しています。
コード化を複数人で推進する際、意図せぬデグレードが発生して開発の足枷になる場合があります。コード規約などのルールを整備して徹底させるということも重要ですが、今回はAWSのCodeシリーズ(CodeBuild、CodePipeline)を使って機械的に統制をとる方法を解説します。
なお、今回使用するIaCツールはTerraformです。
IaCを進める上で重要な要素
集団でコードを開発してリソースを作成する場合、重要な要素は以下2つです。
- 品質の担保
複数人でコードを開発すると、作成者によって記述方法に差が出てしまうことがあります。コードによって書き方が異なると、インフラ運用者は記述に差があることを理解した上で運用する必要があり、改修の妨げになることがあります。また、脆弱性を生む原因にもなるため、記述を統一させる仕組みが必要になります。 - 競合の防止
作成したコードを使って偶然にも2人以上が同時に同じ環境へリソースを作ろうとした場合、競合が発生して想定通りにリソースが作成できない・動作しない、といったことが発生する可能性があります。Terraformの排他制御機能を使うなど、同時にリソースの作成を行えないようにする仕組みが必要になります。
AWS Codeシリーズを用いた実装方法
上記で述べた重要な要素を盛り込んだ仕組みをAWS Codeシリーズで実装します。構成を以下に記載します。この構成はいわゆるCI/CD(継続的インテグレーション/継続的デリバリー)と呼ばれるものです。

Sourceステージ
Sourceステージではバージョン管理システム(VCS)を指定します。今回はGitHubを指定していますが、AWSのサービスであるCodeCommitを使用することも可能です。
Testステージ
TestステージはCodeBuildで実装します。本ステージでは以下の処理を実行します。
- 構文チェック
Terraformの構文チェックツールであるtflint※1を使用することにより、予め定義したルールに沿ってコードが記述されているかをチェックします。チェック後、結果をレポート出力します。 - 静的解析
Terraformの静的解析ツールであるtfsec※2を使用することにより、コードにセキュリティ上の問題が無いかをチェックします。チェック後、結果をレポート出力します。 - dry run
terraform plan
コマンドを実行し、リソース作成前の動作確認を行います。
※1 tflint : https://github.com/terraform-linters/tflint
※2 tfsec : https://github.com/aquasecurity/tfsec
上記3つの処理を行うことにより、品質の担保を実現することができます。CodeBuildで処理を実装するためには、処理の定義を行うbuildspec.yaml
が必要になります。buildspec.yaml
のサンプルを以下に記載します。buildspecの書き方はこちらを参考にしてください。
version: 0.2
env:
exported-variables:
- BuildID
- BuildTag
phases:
install: //installフェーズでtflint、tfsec、terraformをインストールしています
commands:
- "echo Installing tflint"
- "curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash"
- "echo Installing tfsec"
- "curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash"
- "echo Installing tfenv"
- "git clone https://github.com/tfutils/tfenv.git ~/.tfenv"
- "ln -s ~/.tfenv/bin/* /usr/local/bin"
- "tfenv install ${TF_VERSION}"
- "tfenv use ${TF_VERSION}"
pre_build: //pre_buildフェーズではレポート出力用のディレクトリを作成しています
commands:
- "mkdir -p ./reports/tfsec/"
- "mkdir -p ./reports/tflint/"
build: //buildフェーズではtflint、tfsecを実行して結果をxml形式で出力しています。また、terraform planを実行しています
commands:
- "cd ${RESOURCE_PATH}"
- "echo Executing tflint"
- "tflint --init"
- "tflint --chdir=./ --no-color --minimum-failure-severity=${MINIMUM_FAILURE_SEVERITY}"
- "tflint --chdir=./ --no-color --minimum-failure-severity=${MINIMUM_FAILURE_SEVERITY} --format=junit > ../../reports/tflint/report.xml"
- "echo Executing tfsec"
- "tfsec -s --tfvars-file terraform.auto.tfvars --no-color ."
- "tfsec -s --tfvars-file terraform.auto.tfvars --no-color . --format junit > ../../reports/tfsec/report.xml"
- "echo Executing terraform plan"
- "terraform init -input=false -no-color"
- "terraform plan -input=false -no-color"
post_build: //post_buildフェーズでは責任者へ実行結果のURLを通知するための情報を取得しています
commands:
- "export Build_Project_Name=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`"
- "export Build_ID=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"
reports: //レポートのパスと形式を指定しています
reports:
files:
- "reports/tfsec/report.xml"
- "reports/tflint/report.xml"
file-format: JUNITXML
なお、buildspec内で使用している以下の環境変数はCodeBuildのビルドプロジェクトを作成する際に設定します※1。
- TF_VERSION
Terraformのバージョン。変数化することによりバージョンアップにも対応することができる。 - RESOURCE_PATH
実行するコードが格納されているディレクトリのパス。 - MINIMUM_FAILURE_SEVERITY
tfsecを実行した際、エラーとして通知する最低重要度。この指定を変数化することにより、より厳しいチェックを実行したり、チェックを緩くしたりすることができる※2。
※1 ビルドプロジェクトの作成 (コンソール) - 環境 : https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/create-project-console.html#create-project-console-environment
※2 tfsec - usage : https://aquasecurity.github.io/tfsec/v1.18.0/guides/usage/
レビュー/承認ステージ
CodePipelineの機能を使用し、Testステージの結果をSNSを通じて責任者へ通知します。通知を受けた責任者は結果を確認し、承認/却下を決定します。なお、CodeBuildを実行した結果のURLは以下の形式で生成されます。
https://{Region}.console.aws.amazon.com/codesuite/codebuild/{AWS_ACCOUNT_ID}/projects/{Build_Project_Name}/build/{Build_Project_Name}%3A{Build_ID}/?region={Region}
buildspec内でビルドプロジェクト名(Build_Project_Name)とビルドID(Build_ID)を取得してエクスポートすることにより、その値を変数としてレビュー/承認ステージに渡すことができます。URLの設定画面は以下の通りです。

実際にレビュー/承認ステージまで処理が進んだ際の通知メールと承認画面がこちらです。
通知メール

承認画面

[承認します]をクリックすることにより、次のステージであるリソース作成ステージに進むことができます。本ステージを実装することで競合の防止を実現できます。
リソース作成ステージ
レビュー/承認ステージで承認された変更はリソース作成ステージに進みます。本ステージはTestステージと同様にCodeBuildを使用して実装します。本ステージではterraform apply
を実行します。buildspecの内容は以下の通りです。
version: 0.2
phases:
install: //installフェーズではtfenv経由で任意のバージョンのterraformをインストール
commands:
- "echo Installing tfenv"
- "git clone https://github.com/tfutils/tfenv.git ~/.tfenv"
- "ln -s ~/.tfenv/bin/* /usr/local/bin"
- "tfenv install ${TF_VERSION}"
- "tfenv use ${TF_VERSION}"
pre_build: //pre_buildフェーズではterraformの初期化を実施
commands:
- "cd ${RESOURCE_PATH}"
- "terraform init -input=false -no-color"
build: //buildフェーズではterraform applyを実行してリソース作成を実施
commands:
- "echo Executing terraform apply"
- "terraform apply -input=false -no-color -auto-approve"
最後に
今回はインフラコード化(IaC)で重要な「品質の担保」と「競合の防止」をAWS Codeシリーズで実現する方法を紹介しました。インフラコード化はコードを作って終わりではありません。コードを使って如何に統制をとりながらインフラを運用していくかが重要です。
本ブログが皆さんの参考になれば幸いです。
CTCは、AWSのビジネス利活用に向けて、お客様のステージに合わせた幅広い構築・運用支援サービスを提供しています。
経験豊富なエンジニアが、ワンストップかつ柔軟にご支援します。
ぜひ、お気軽にお問い合わせください。