Terraform で AWS Control Tower のガードレール/コントロールを管理する

Control Towerのガードレール/コントロールを全てTerraformで作成・更新する未来も近い!
2022.12.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも、ちゃだいん(@chazuke4649)です。

少し前に、Terraform の AWS Provider が AWS Control Tower のガードレール/コントロール の リソース と データソース をサポートしました!

aws_controltower_control | Resources | hashicorp/aws | Terraform Registry

aws_controltower_controls | Data Sources | hashicorp/aws | Terraform Registry

いわゆるControl TowerのAPIが公開されたので、その後Terraform側も対応したという感じですね。 CloudFormation版はこちらです。

AWS CLIリファレンスはこちらです。

さっそく試してみましょう。

既存コントロールを参照

まず、データソースを使って既存OU/アカウントにて有効化されているガードレール/コントロール(以降コントロール)の一覧を見てみましょう。

以下のようなTerraformコードを作成します。(ほぼ先述の公式ドキュメントママです)

control.tf

data "aws_organizations_organization" "main" {}

data "aws_organizations_organizational_units" "main" {
  parent_id = data.aws_organizations_organization.main.roots[0].id
}

output "children" {
  value = data.aws_organizations_organizational_units.main.children
}


## Security OU
data "aws_controltower_controls" "security" {

  target_identifier = [
    for x in data.aws_organizations_organizational_units.main.children :
    x.arn if x.name == "Security"
  ][0]

}

output "controls_security" {
  value = data.aws_controltower_controls.security.enabled_controls
}

こちらを適用後、以下のように有効化されているコントロールの一覧を取得することができました。

% terraform output controls_security
tolist([
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_AUDIT_BUCKET_DELETION_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_AUDIT_BUCKET_PUBLIC_READ_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_AUDIT_BUCKET_PUBLIC_WRITE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_CLOUDWATCH_LOGS_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_VALIDATION_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDWATCH_EVENTS_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_AGGREGATION_AUTHORIZATION_POLICY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_AGGREGATION_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_RULE_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CT_AUDIT_BUCKET_ENCRYPTION_CHANGES_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CT_AUDIT_BUCKET_LIFECYCLE_CONFIGURATION_CHANGES_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CT_AUDIT_BUCKET_LOGGING_CONFIGURATION_CHANGES_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CT_AUDIT_BUCKET_POLICY_CHANGES_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_DETECT_CLOUDTRAIL_ENABLED_ON_SHARED_ACCOUNTS",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_IAM_ROLE_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_LAMBDA_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_LOG_GROUP_POLICY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_REGION_DENY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_SNS_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_SNS_SUBSCRIPTION_CHANGE_PROHIBITED",
])

新規コントロールを登録

次にリソースを使って新しくコントロールをOUに適用させます。

残念ながら、現時点では全てのコントロールのリスト あるいは 有効化されていないコントロールのリスト を取得するAPI/CLIがない模様なので、マネジメントコンソールにARNを見に行くなどの対応が必要です。(アップデートに期待!)

今回は既存のOU同士を比較し、差分のコントロールを少ない方のOUに適用させてみます。

先ほどのSecurityOUと同じように、既存OUである、WorkloadsOUとSampleOUの有効化されているコントロールを取得します。

control.tf

data "aws_organizations_organization" "main" {}

data "aws_organizations_organizational_units" "main" {
  parent_id = data.aws_organizations_organization.main.roots[0].id
}

output "children" {
  value = data.aws_organizations_organizational_units.main.children
}

## Workloads OU
data "aws_controltower_controls" "workloads_ou" {

  target_identifier = [
    for x in data.aws_organizations_organizational_units.main.children :
    x.arn if x.name == "WorkloadsOU"
  ][0]

}

output "controls_workloads_ou" {
  value = data.aws_controltower_controls.workloads_ou.enabled_controls
}


## Sample OU
data "aws_controltower_controls" "sample_ou" {

  target_identifier = [
    for x in data.aws_organizations_organizational_units.main.children :
    x.arn if x.name == "SampleOU"
  ][0]

}

output "controls_sample_ou" {
  value = data.aws_controltower_controls.sample_ou.enabled_controls
}

2つの差分を取ります。

% terraform output controls_sample_ou > controls_sample_ou.txt
% terraform output controls_workloads_ou > controls_workloads_ou.txt
% diff controls_sample_ou.txt controls_workloads_ou.txt
15a16,17
>   "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS",
>   "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED",

この2つのコントロールをSampleOUに適用します。

control_sample.tf

locals {
  additional_controls = {
    sample_ou = [
      "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS",
      "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED",
    ]
  }
}

resource "aws_controltower_control" "sample_ou" {
  for_each           = toset(local.additional_controls.sample_ou)
  control_identifier = each.value
  target_identifier = [
    for x in data.aws_organizations_organizational_units.main.children :
    x.arn if x.name == "SampleOU"
  ][0]
}

ポイントとしては、先ほどの差分のコントロールのARNをLocal変数にリスト型で記入しました。 そして、resourceブロックでは、for_eachを使用し、ARNの数だけ繰り返し作成する形にしました。

問題なければ、terraform planを実行します。

Terraform will perform the following actions:

  # aws_controltower_control.sample_ou["arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS"] will be created
  + resource "aws_controltower_control" "sample_ou" {
      + control_identifier = "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS"
      + id                 = (known after apply)
      + target_identifier  = "arn:aws:organizations::999999999999:ou/o-xxxxexample/ou-xxxxx-bsfl6bmj"
    }

  # aws_controltower_control.sample_ou["arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED"] will be created
  + resource "aws_controltower_control" "sample_ou" {
      + control_identifier = "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED"
      + id                 = (known after apply)
      + target_identifier  = "arn:aws:organizations::999999999999:ou/o-xxxxexample/ou-xxxxx-bsfl6bmj"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

## 一部値をマスクしています

問題なければ、terraform applyします。

Control Towerコンソール>組織>SampleOUにてコントロールを確認すると、2つのコントロールが有効化されていることを確認できました。

検証は以上です。

余談)プレビュー版コントロールはいける?

パブリックプレビュー扱いとなっている re:Invent2022アップデートによるコントロールライブラリにて追加の新規コントロール(リリース日: 2022.11.28)はTerraformで操作可能でしょうか?

現時点(2022.12.23)で、以下の有効化を試したところ、登録することができました。

  • 名前: [SH.EC2.1] EBS スナップショットはパブリックに復元可能であってはならない - プレビュー
  • 識別子: arn:aws:controltower:ap-northeast-1::control/FLYKUCWHEFPS
% terraform output controls_sample_ou
controls_sample_ou = tolist([
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_CLOUDWATCH_LOGS_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDTRAIL_VALIDATION_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CLOUDWATCH_EVENTS_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_AGGREGATION_AUTHORIZATION_POLICY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_AGGREGATION_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_CONFIG_RULE_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_IAM_ROLE_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_LAMBDA_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_LOG_GROUP_POLICY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_REGION_DENY",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_SNS_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/AWS-GR_SNS_SUBSCRIPTION_CHANGE_PROHIBITED",
  "arn:aws:controltower:ap-northeast-1::control/FLYKUCWHEFPS",
])

ただし、あくまでプレビュー版であるため本番環境での利用はNGですし、ARNも暫定的な値っぽいです。

コントロールライブラリのGAを待ち、さらに全てのコントロールがTerraformで管理できる未来に期待しましょう!