こんにちは。hey セキュリティ本部の清水です。
複数のAWSメンバーアカウントに対して Terraform を実行する環境を CodeBuild 上に構築したので、今回はその内容を記載したいと思います。
そもそも、なぜ Terraform の実行環境を構築したのかというと、セキュリティのベースライン設定を適用する実行環境が欲しかったからです。セキュリティのベースライン設定とは何かというと、AWSアカウントをセキュリティの観点からより安全にする設定の集合(AWS Config の有効化、Amazon GuardDuty の有効化)のこと、ぐらいに捉えていただければ大丈夫です。
組織によって、ベースライン設定にどんな設定を含めるかは異なると思います。hey では、AWS Foundational Security Best Practices controls を参考に、AWSメンバーアカウント作成時にセキュリティのベースライン設定として含める項目を選定しました。今回は Terraform の実行環境を CodeBuild に構築した内容がメインなので、セキュリティのベースライン設定については深く説明しません。
検討した構成
Terraform をどこで実行するか、CodeBuild 以外の環境も検討しました。以下は導入を検討した実行環境です。
- GitHub Actions
- Control Tower Account Factory for Terraform
- CloudFormation
GitHub Actions 上で Terraform を実行して AWS リソースを操作するのは、GitHub の権限管理 ≒ AWS の権限管理となりそうなので止めました。一見、AWS の権限管理を正しくできていても、GitHub の権限管理が適当だと業務に関係のないエンジニアでも実質的に AWS のリソース操作が可能となるリスクがあるからです。このため、セキュリティインシデントに繋がる可能性があると考えました。
Control Tower Account Factory for Terraform は、他サイトの提供する情報などを参考にすると、実行環境を構築するのに306個のAWSリソースを作成する必要があり、適切に設定しないと月額約400ドルのランニングコストが発生するなど、やりたいことに対するオーバースペック気味を感じたので深く調査する前に止めました(今後見直す可能性はあります)。
CloudFormation は、そもそも Terraform ではないのですが、会社のエンジニアは Terraform の方が扱える人が多いので採用を見送りました(CloudFormation StackSets など、ちゃんと使えば便利そうではありますが)。
システム構成
今回構築した、複数のAWSメンバーアカウントに対して Terraform を実行する CodeBuild 環境の構成図は以下の通りとなります。CodeBuildの実行IAMロールやログの保管場所(S3, CloudWatch Logs)など、細かいものは省略しています。
設計・実装時において考慮したポイントをいくつか紹介します。
GitHub 上の Terraform ソースコードの取得方法
CodeBuild で用意されている GitHub からのソースコードの取得方法は、OAuth または 個人用アクセストークン となります。どちらの方法でもそこまで苦労せずにソースコードを取得できるようになるのですが、この方法ではCodeBuildに対して GitHub に関する余分な操作権限(ソースコードの変更権限や、他レポジトリの参照権限など)を与えてしまいます。また、OAuth または 個人用アクセストークンは、個人の GitHub ユーザーアカウントに紐づくので、その人が部署異動や退職した時に問題が起こり得ます。
このような理由から、少し設定は面倒となりますが、GitHub のデプロイキー 機能を利用してソースコードを取得するようにしました。デプロイキーを利用すれば、個人のアカウントと紐づけることがなく、CodeBuild にGitHub に関する余分な権限を与えずにソースコードを取得できるようになります。ちなみに、GitHub Apps を利用しても権限を細かく指定できますが、少し設定手順が複雑になるため、今回はデプロイキーによる方法を採用しました。
以下は、CodeBuild でデプロイキーを利用してソースコードを取得する buildspec.yml のコード例です。デプロイキーの秘密鍵は、Parameter Store に保存して、CodeBuild のIAMロールに Parameter Store の値の取得権限を付与して、実行時に Parameter Store の値を取得します。
env: variables: org_name: 'sample_org' repo_name: 'sample_repo' parameter-store: deploy_key: 'sample_deploy_secret_key' phases: pre_build: commands: - echo "Host repo" >> /root/.ssh/config - echo " Hostname github.com" >> /root/.ssh/config - echo " IdentityFile=/root/.ssh/deploy_key" >> /root/.ssh/config - echo "${deploy_key}" > /root/.ssh/deploy_key - chmod 400 /root/.ssh/deploy_key - git clone git@repo:${org_name}/${repo_name}.git
Terraform のプロバイダ設定
management account 上の CodeBuild から、どうやって他 member account の AWS リソースを操作するかというと、OrganizationAccountAccessRole を利用しています。CodeBuild が Terraform を適用するアカウントの OrganizationAccountAccessRole を引き受けることで、そのアカウントの AWS リソースに対する操作権限を得ることができます。 以下は、Terraform での OrganizationAccountAccessRole を引き受ける provider の設定例です。
provider "aws" { region = "ap-northeast-1" alias = "ap_northeast_1" assume_role { role_arn = join(":", ["arn:aws:iam:", var.account_id, "role/OrganizationAccountAccessRole"]) session_name = "terraform" } } resource "aws_ebs_encryption_by_default" "ap_northeast_1" { enabled = true provider = aws.ap_northeast_1 }
workspace 機能の利用
私は普段 Terraform を書くときは、以下のように適用対象ごとにディレクトリを切って共通モジュールを呼び出して適用する運用をよくします(hey 全体でもディレクトリやモジュールで分けて適用対象を区切るのが主流だと思います)。
terraform ├── development │ └── main.tf <- 内部で module.tf を読み込む ├── production │ └── main.tf <- 内部で module.tf を読み込む └── modules └── module.tf
今回はディレクトリではなくて、 workspace の機能を利用して適用対象を分けました。
terraform workspace list default development * production
なぜかというと、なるべく外部からの入力によって Terraform の適用対象 AWS アカウントを決定しやすくするためです。
Terraform を実行する環境を CodeBuild 上に構築した背景には、新規に作成した AWS アカウントにセキュリティのベースライン設定を適用したいという理由があります。将来的には、AWS アカウント作成パイプラインの処理工程の一つに、今回構築したCodeBuildによるセキュリティのベースライン設定を組み込みたく、パイプラインの前工程からの入力を受け付けるときに、ディレクトリを更新するよりも workspace を更新する方がやりやすいだろうと判断しました。ただし、この決定は今後実際にパイプラインを形成する際に問題に直面した場合は変更するかもしれません。
まとめ
複数のAWSメンバーアカウントに対して Terraform を実行する環境について、CodeBuild での実現方法の一例を紹介させていただきました。参考となれば幸いです。
採用絶賛募集中!!
今回はセキュリティというよりSRE(?)ぽい話のような気もしますが、 hey ではセキュリティエンジニア(SREエンジニアも)を募集しています!!脆弱性診断やパブリッククラウドのセキュリティ強化など取り組むべき課題はたくさんあります。セキュリティエンジニアの方、もしくは今までSREエンジニアとしてやってきたけどセキュリティにも取り組みたい方、などご興味ありましたら、カジュアル面談からお気軽にお問い合わせください。