俺のTerraform Pipeline #devio2022
こんにちは!AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。
Developers.IO 2022 〜技術で心を揺さぶる 3 日間〜 にて、「俺の Terraform Pipeline」というテーマでお話しさせていただきました。
Terraform で CI/CD パイプラインを組むならどのような構成が取れるのか、構成例の 1 つとしてご紹介させていただきました。
動画
スライド
想定する視聴者
- そろそろ CI/CD パイプラインで Terraform を使いこなしてみようかなと言う人
- Terraform のコードスキャン(動画だと tfsec)に興味がある人
発表ネタにしたブログ
今回は以下のブログについて、情報を掻い摘んで動画にしました。もしよければ重ねてご覧ください。
情報のアップデート
ここからは先ほど紹介したブログおよび動画時点で気がつかず、今になって紹介したいことがあるので、ここからは「私自身の成長記録」をつらつらと綴っていこうと思います。
みなさんも、以前のブログ、動画、このブログでムキムキの Terraform おじさんへの階段を駆け上がっていきましょう。
Terraform の Docker イメージ
まずはじめに、Amazon ECR Public Gallery で Terraform の Docker イメージが配布されていたことです。
動画時点では、terraform plan/apply
コマンド用の CodeBuild プロジェクトで、毎度INSTALL
フェーズにて Terraform のインストールを行なっていました。
version: 0.2
env:
exported-variables: - BuildID - BuildTag
phases:
install:
runtime-versions:
golang: 1.14
commands: - "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:
commands: - "terraform init -input=false -no-color"
build:
commands: - "terraform plan -input=false -no-color"
post_build:
commands: - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`" - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"
Amazon ECR Public Gallery で配布された Terraform の Docker イメージを利用すると先ほどのINSTALL
フェーズを省略することができます。
version: 0.2
env:
exported-variables: - BuildID - BuildTag
phases:
pre_build:
commands: - "terraform init -input=false -no-color"
build:
commands: - "terraform plan -input=false -no-color"
post_build:
commands: - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`" - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"
もたらされる効果
ビルドログを確認するとネットワークの状況にもよりますが、INSTALL フェーズには「6 秒」かかったという記録が取れました。
一方で INSTALL フェーズを短縮した場合、INSTALL フェーズは「1 秒未満」まで短縮できました。
CodeBuild は実行時間あたりに対して課金が行われるため「コスト最適化」が微々たるものですが見込めます。
Build URL
ブログ時点では、CodeBuild の実行結果をレポート出力する方法として次の形式で出力を行なっていました。
https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TFSEC.BuildID}/build/#{TFSEC.BuildID}%3A#{TFSEC.BuildTag}/?region=${AWS::Region}
ご覧の通り、パワープレイな感じがするので調査したところ、CodeBuild でCODEBUILD_BUILD_URL
という環境変数が同じ用途で使えるのでそちらにアップデートを行います。
version: 0.2
env:
exported-variables:
- - BuildID
- - BuildTag
+ - BUILD_URL
phases:
pre_build:
commands: - "terraform init -input=false -no-color"
build:
commands: - "terraform plan -input=false -no-color"
post_build:
commands:
- - "export BuildID=`echo $CODEBUILD_BUILD_ID | cut -d: -f1`"
- - "export BuildTag=`echo $CODEBUILD_BUILD_ID | cut -d: -f2`"
+ - "export BUILD_URL=`echo $CODEBUILD_BUILD_URL`"
Cloudformartion テンプレートもかなりスッキリしたのがわかります。
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Sub "${PrjPrefix}-tf-pipeline"
ArtifactStore:
EncryptionKey:
Id: !GetAtt KeyS3Arthifact.Arn
Type: "KMS"
Location: !Ref BucketArtifacts
Type: "S3"
RoleArn: !GetAtt RoleTfPipelne.Arn
Stages:
- Name: "Source"
Actions:
- Name: "CodeCommit_Source"
ActionTypeId:
Category: "Source"
Owner: "AWS"
Provider: "CodeCommit"
Version: "1"
Configuration:
RepositoryName: !GetAtt CodeCommit.Name
BranchName: !Ref BranchName
PollForSourceChanges: false
OutputArtifacts:
- Name: "Artifact_Source_CodeCommit_Source"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 1
- Name: "tfsec_Stage"
Actions:
- Name: "Terraform_Security_Analysis"
Namespace: TFSEC
ActionTypeId:
Category: "Build"
Owner: "AWS"
Provider: "CodeBuild"
Version: "1"
Configuration:
ProjectName: !Ref ProjectTfsec
InputArtifacts:
- Name: "Artifact_Source_CodeCommit_Source"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 1
- Name: "Terraform_Stages"
Actions:
- Name: "Terraform_Security_Analysis_Manual_Review"
ActionTypeId:
Category: "Approval"
Owner: "AWS"
Provider: "Manual"
Version: "1"
Configuration:
CustomData: "tfsec review"
- ExternalEntityLink: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TFSEC.BuildID}/build/#{TFSEC.BuildID}%3A#{TFSEC.BuildTag}/?region=${AWS::Region}"
+ ExternalEntityLink: "#{TFSEC.BUILD_URL}"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 1
- Name: "Terraform_Plan"
Namespace: "TERRAFORM"
ActionTypeId:
Category: "Build"
Owner: "AWS"
Provider: "CodeBuild"
Version: "1"
Configuration:
ProjectName: !Ref ProjectTfplan
InputArtifacts:
- Name: "Artifact_Source_CodeCommit_Source"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 2
- Name: "Terraform_Plan_Manual_Review"
ActionTypeId:
Category: "Approval"
Owner: "AWS"
Provider: "Manual"
Version: "1"
Configuration:
CustomData: "Terraform plan review"
- ExternalEntityLink: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codebuild/${AWS::AccountId}/projects/#{TERRAFORM.BuildID}/build/#{TERRAFORM.BuildID}%3A#{TERRAFORM.BuildTag}/?region=${AWS::Region}"
+ ExternalEntityLink: "#{TERRAFORM.BUILD_URL}"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 3
- Name: "Terraform_Apply"
ActionTypeId:
Category: "Build"
Owner: "AWS"
Provider: "CodeBuild"
Version: "1"
Configuration:
ProjectName: !Ref ProjectTfapply
InputArtifacts:
- Name: "Artifact_Source_CodeCommit_Source"
RoleArn: !GetAtt RoleTfPipelne.Arn
RunOrder: 4
Snyk IaC もイイぞ
Snyk IaC は、tfsec の代替案として有効なソリューションです。
最近ブログもよく書いているので、重ねてご覧いただければ嬉しいです。
DevelopersIO 2022 で Snyk Japan の相澤様に登壇いただきました。(セッションレポートになります。)
まとめ
「俺の Terraform Pipeline」の登壇レポートでした!「俺の Terraform Pipeline」を作ろうとしている方の参考になれば幸いです。
以上、AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!