この記事は Nikkei Advent Calendar 2020 16日目の記事です。
こんにちは、日本経済新聞社(以下日経)API・バックエンドチームの成田です。
AWSにはセキュリティなどの観点からどのアカウントでも設定すべき共通のベストプラクティスが存在します。日経では数十ものAWSアカウントを利用しており、これら一つ一つに手作業で適用していくのは骨が折れます。これを自動化していくのが今回の目的です。
AWSはAWS Control Towerというサービスを展開しており、AWSが定めたベストプラクティスに基づきAWS CloudTrail、AWS Config、AWS SSOなどのセットアップをしてくれます。目的どおりの機能で非常に便利そうなのですが、以下のような懸念点がありました。
- 東京リージョンで対応していない(2020年12月現在)
- アカウントごとに設定を変えられない
- CloudFormationよりTerraformのほうが使い勝手が良い(と感じた
- 既存アカウントへの適用が2020年1月時点(このプロジェクト開始時)で出来なかった... など
そこでこうした点に対応するため、Terraform + GitHub + CircleCIを用いて、Control Towerのようなオリジナルのテンプレートを作成し、新規アカウント及び既存アカウントに適用する仕組みを開発しました。今回は、テンプレートの内容や、Terraformを実行するためのディレクトリ構造、作業の流れについて説明していきます。
テンプレートの内容
現在、テンプレートとして設定する内容は以下の通りです
- AWS CloudTrailの設定 + ログの集約
- Amazon GuardDutyの設定 + 検査結果の集約
- AWS Configの設定 + データ集約
- Amazon S3のパブリックアクセスブロック
- Amazon EBSのデフォルト暗号化
- AWS IAMのパスワードポリシー設定
- デフォルトの AWS VPC使用禁止 ...など
このように、AWSのセキュリティベクトプラクティスの中でも、アカウント全体に関する設定を入れています。RDSなど個別のリソースに関してはついてはAWS configで監視を行います。また、セキュリティに関するログをログアカウントに集約し、外部委託のSOCサービスとの連携を行っています。設定は都度都度追加・更新しています。
ディレクトリ構造
上記の設定は、可能な限り全アカウントに適用することが望ましいですが、特に既存のアカウントに適用する場合、稼働中のシステムに影響が出ないよう一部設定を除きたいケースがあります。例えば、S3のwebホスティングを使用しているアカウントでは、Amazon S3のパブリックアクセスブロック
の設定が不可能です。逆に、IAMやConfigなどのより厳しいセキュリティ設定が求められるアカウントもありますし、開発系アカウントのみで実験的に新設定を試しいといったケースもあります。そこで、アカウントごとにテンプレートを柔軟に調整することが出来るようなディレクトリ構造を目指しました。
今回採用したディレクトリ構造は以下のようになります。
├── base_account
│ ├── terraform_config.tf
│ ├── set_config.sh
│ ├── aws_config.tf
│ ├── guardduty.tf
│ ├── cloudtrail.tf
│ ...
├── client_accounts
│ ├── target_account1_1234567890
│ │ ├── terraform_config.tf
│ │ ├── set_config.sh
│ │ ├── aws_config.tf
│ │ ├── guardduty.tf
│ │ ├── cloudtrail.tf
│ │ ...
│ ├── target_account2_0987654321
│ ...
├── files
│ └── policy
├── modules
│ ├── aws_config
│ │ ├── main.tf
│ │ ├── output.tf
| | └── variables.tf
│ ├── guardduty
│ ...
├── scripts
...
このように、client_accounts
以下アカウントごとにフォルダを分け、それぞれのルートでTerraformを実行する形式にしました。base_account
が基本テンプレートとなっており、リソースごとのTerafformファイルが入っています。これをまずはコピーし、フォルダを作成します。その後、必要に応じてmoduleに渡す変数を変更したり、ファイルを追加・削除したりすることで、アカウントごとのテンプレートを作成します。
また、base_account
にはset_config.sh
が含まれています。これは.aws/config
を編集するスクリプトで、以下のようになっています。TerraformはSwitch Roleの設定が可能となっており(参考)、NikkeiTemplateRole
はそのためのroleです。各アカウントに予め作成しておく必要があります。AdministratorAccessポリシーをアタッチし、信頼されたエンティティとしてbackendアカウントを選択します。
# スイッチロール先のロール情報を書き込む
aws configure set role_arn arn:aws:iam::{{account_id}}:role/NikkeiTemplateRole --profile {{folder_name}}
aws configure set source_profile admin --profile {{folder_name}}
CircleCI上では、まずAssumeRoleの権限を持ったbackendアカウントのAccessKeyでログインします。各フォルダで上記のスクリプト(set_config.sh)を実行しすることで、Switch Roleをした上でTerraformコマンドを実行することが出来ます。
各アカウントの関係をまとめると以下のようになります。厳密にはbackendアカウントとログアカウントもTerraformでテンプレートを適用しています。

作業の流れ
ある対象アカウントにテンプレートを適用する際の流れをざっとまとめます。
- 下準備
対象アカウントにSwitch Roleのためのroleを作成し、信頼されたエンティティとしてbackendアカウントを選択します。また、backendアカウントでbackendS3バケットのアクセスポリシーを編集します。
- アカウントフォルダ作成
対象アカウント用フォルダを作成します。base_accountフォルダを元に作成し、追加・削除したい設定があればここで適宜編集します。
- Pull Request + terraform plan
Pull Requestを送ります。このときCircleCI上で terraform plan
が走るような設定にしました。レビュアーはplan結果を確認し、レビューを行います。

- terraform apply
問題なければmaster branchにマージし、更にdeploy branchを作成すると、CircleCI上で terraform plan
+ terraform apply
が走り、テンプレートが適用されます。
- 後処理
一部の処理はTerraformだけで完結しません。例えばAWS Configのrecorderを有効にする、GuardDutyの検査結果を集約するといった作業が必要になるので、公式scriptや自作scriptを利用します。
終わりに
本記事ではTerraform、GitHub、CircleCIを利用して、アカウントにテンプレートを導入する仕組みについて書いていきました。今後もこのテンプレートを拡充したいと思っており、例えば、oktaなどのIdPとAWS SSOの連携などもこの取り組みの中で行っていきたいです。一方、Control Towerが東京リージョンで使えるようになる日も遠くないかもしれません。今後のAWSのサービス発表に注目ですね。