[アップデート] Control Tower のガードレール適用が API と CloudFormation 経由で行える様になりました

2022.09.02

こんにちは、大前です。

Control Tower について以下のアップデートがありましたので、紹介したいと思います。

どんなアップデートか

Control Tower のガードレール設定を行うための API が提供されました。また、CloudFormation を利用した変更もできる様になっています。

端的に書くと大したアップデートではないですが、Control Tower を活用している方からすると大きなアップデートではないでしょうか。

本アップデート以前は Control Tower のガードレールを手作業で有効化する必要がありました。ガードレールは多数存在するため、単純に各ガードレールを手作業で有効化していくのは大変ですし、手作業ゆえの設定ミスもリスクとしてあったと思います。

今回のアップデートで API や CloudFormation を利用したガードレールの有効化が可能となったため、単純に作業時間が短縮できますし、ガードレールの最新状態を管理しやすくなったかと思います。

やってみた

では実際に今回のアップデートを利用してガードレールの設定変更をやってみます。

執筆時点では AWS CLI v2 にて Control Tower API の対応がされていない様なので、今回は CloudFormation のみの確認としています。(v1 では対応している様なので、どうしても早く CLI で有効化したい、という場合は v1 でお試しください)


以下に、いくつかのパターンについて、利用した CloudForamtion テンプレートとその結果を記載していきます。

具体的なテンプレートは後ほど記載しますが、ControlIdentifier(有効化対象のガードレールの ARN)と TargetIdentifier(ガードレール適用先となる OU) を指定する形式の様です。

また、ControlIdentifier に指定する ARN については、以下ドキュメントにて一覧を確認可能です。


パターン 1 : 有効化されていないガードレールを CloudFormation で有効化する

まずはシンプルな有効化作業です。

以下のテンプレートを利用しました。リージョンは Control Tower を有効化しているホームリージョンに置き換えてください。

また、有効化するガードレールとしては Amazon EC2 インスタンスの Amazon EBS 最適化が有効になっているかどうかを検出する を指定しています。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Setup Control Tower Control"

Resources:
  TestControl:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EBS_OPTIMIZED_INSTANCE"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"


上記テンプレートを利用して CloudFormation スタックを作成すると、約 3分ほどでスタックの作成が完了しました。


スタック作成の完了後、Control Tower の画面にて、指定した OU にガードレールがアタッチされていることが確認できます。今回は Sandbox という OU を対象にしています。


パターン 2 : CloudFormation で有効化したガードレールを無効化

続いて、CloudFormation で有効化したガードレールを無効化します。

結論から述べると、CloudFormation のスタックを削除することでガードレールが対象の OU から外れます。

以下はスタック削除後の状態です。先ほど追加された Sandbox がなくなっていることがわかるかと思います。


下記のように、DisabledControl を利用して無効化ができないか試してみましたが、"Unrecognized resource types" のエラーが出てしまったので、どうやら現状は EnabledControl のみサポートされている様です。(念の為、"DisableControl" など文字列を変えて試してみましたが、同じ結果でした)

AWSTemplateFormatVersion: "2010-09-09"
Description: "Setup Control Tower Control"

Resources:
  TestControl:
    Type: "AWS::ControlTower::DisabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EBS_OPTIMIZED_INSTANCE"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"


パターン 3 : 手動で有効化済みのガードレールに対して CloudFormation で有効化を実行してみる

続いて、既に手動で有効化されているガードレールに対し、CloudFormation で有効化のリクエストを実行してみました。

結果としては失敗し、下記のように AlreadyExists というエラーが出ました。後述しますが、既に手動で有効化済みのガードレールはインポートができますので、インポートを利用して CloudFormation スタックの管理下におきましょう。


パターン 4 : 11個以上のガードレールを CloudFormation で有効化してみる

公式ドキュメントには下記の様に「同時操作は 10個まで」と記載があるので、11個以上のガードレール(全て有効化されていないもの)を同時に有効化してみます。

The limit for EnableControl and DisableControl updates in AWS Control Tower is 10 concurrent operations.


下記のテンプレートを作成してみました。11個のガードレールを有効化するテンプレートになっています。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Setup Control Tower Control"

Resources:
  TestControl01:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ENCRYPTED_VOLUMES"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl02:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EBS_OPTIMIZED_INSTANCE"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl03:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EC2_VOLUME_INUSE_CHECK"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl04:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_INSTANCE_PUBLIC_ACCESS_CHECK"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl05:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_SNAPSHOTS_PUBLIC_PROHIBITED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl06:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_STORAGE_ENCRYPTED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl07:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICTED_COMMON_PORTS"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl08:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl09:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl10:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl11:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_S3_BUCKET_PUBLIC_READ_PROHIBITED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"


実行したところ、下記の様なエラーが発生し、スタック作成が失敗しました。


また、CloudFormation のスタック作成イベントを見ていると、全てロールバックされるのではなく、一部が DELETE_SKIPPED となっており、Control Tower 側では一部ガードレールが有効化された状態で残っていました。


上記より、予期せぬ状態になってしまう可能性があるため、一度に 10個以上のガードレールを一気に設定するのは避けたほうがよさそうです。

ただ、あくまで「同時に 10個を超えるガードレール適用が NG」であるため、下記の様に 11個目以降のガードレールを一時的にコメントアウトし、コメントアウトを少しずつ外して変更セットの適用を繰り返せば 1つのスタックで 10個以上のガードレールを管理できます。ただ、結構手間ですし、ガードレールは 10個以上有効化したいケースも多いかと思いますので、改善を期待したいところです。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Setup Control Tower Control"

Resources:
  TestControl01:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ENCRYPTED_VOLUMES"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl02:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EBS_OPTIMIZED_INSTANCE"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl03:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EC2_VOLUME_INUSE_CHECK"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl04:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_INSTANCE_PUBLIC_ACCESS_CHECK"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl05:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_SNAPSHOTS_PUBLIC_PROHIBITED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl06:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RDS_STORAGE_ENCRYPTED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl07:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICTED_COMMON_PORTS"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl08:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl09:
    Type: "AWS::ControlTower::EnabledControl"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_RESTRICT_ROOT_USER_ACCESS_KEYS"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  TestControl10:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_ROOT_ACCOUNT_MFA_ENABLED"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"
  #TestControl11:
  #  Type: "AWS::ControlTower::EnabledControl"
  #  DeletionPolicy: "Retain"
  #  Properties:
  #    ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_S3_BUCKET_PUBLIC_READ_PROHIBITED"
  #    TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"


パターン 5 : 既に有効化済みのガードレールを CloudFormation スタックにインポートする

既に Control Tower が有効化されている環境では、当然ながらガードレール設定が既にされているものと思います。そのため、既に手動で有効化したガードレールを CloudFormation でインポートできるかも試してみます。

下記の様に、既存リソースをインポートするための記法に従い、CloudFormation テンプレートを用意します。

AWSTemplateFormatVersion: "2010-09-09"
Description: "Setup Control Tower Control"

Resources:
  TestControl03:
    Type: "AWS::ControlTower::EnabledControl"
    DeletionPolicy: "Retain"
    Properties:
      ControlIdentifier: "arn:aws:controltower:ap-northeast-1::control/AWS-GR_EC2_VOLUME_INUSE_CHECK"
      TargetIdentifier: "arn:aws:organizations::000011112222:ou/o-aaaabbbb/ou-aaaa-bbbb"


コンソールより、スタックのインポートを進めると、下記のように ControlIdentifierTargetIdentifier の入力を求められるので、テンプレート内と同じ値を指定してスタックの作成を進めます。


スタックの作成を実行したところ、無事にインポートができました。インポートに対応している様ですね。


手順は省略しますが、テンプレート内の DeletionPolicy: "Retain" 部分を削除するようにスタックを更新したのち、スタック自体を削除したところガードレールが外れていたので、問題なくインポートが機能しているものと思われます。

おわりに

Control Tower のアップデートで、ガードレールの有効化/無効化 が API と CloudFormation を利用して実施できる様になりました。

手作業でやる必要があった Control Tower のガードレール有効化作業から解放されると思うと、個人的にはなかなか嬉しいです。


以上、AWS 事業本部の大前でした。

参考