[アップデート]API を使用して AWS Control Tower ランディング ゾーン操作の自動化が可能になりました #AWSreInvent

2023.11.27

こんにちは。たかやまです。

いままでControl Towerのランディングゾーンの操作はコンソールからしかできませんでしたが、今回アップデートによりついにControl Towerのランディングゾーンの操作がAPIより可能になりました。

さきにまとめ

  • 追加のAPIは以下
    • GetLandingZone/ListLandingZones - ランディングゾーンの設定オプションを表示
    • CreateLandingZone/UpdateLandingZone/DeleteLandingZone - ランディングゾーンのリソースを管理
    • ResetLandingZone - ランディングゾーンのドリフトを修正
    • GetLandingZoneOperation - 進行中の変更を監視
  • APIの操作からはリージョン拒否コントロールは非対応
    • リージョン拒否コントロールを利用する場合にはコンソールから設定を実施する
  • CloudFormationにも対応

※ただし、検証時点でAPIまわりの整備がちゃんとされていなかったため後日追記予定
以下のブログで検証してみました。

やってみる

AWS CLI

AWS CLIでやってみようと思ったのですが、アップデート発表時点(11/26)の最新AWS CLI 2.13.38 ではまだ対応していないようでした。

Bump version to 2.13.38 · aws/aws-cli@5c8bec1

ドキュメントとして用意されているので、期待して待ちましょう!

CloudFormation

次にCloudFormationも対応しているとのことで、こちらのシナリオを試してみたいと思います。

シナリオとしては、既存のログアカウントとセキュリティアカウントを使ってランディングゾーンを作成するというものです。そのため事前準備として以下のCloudFormationを実行して各アカウントとControl Tower実行のためのIAMロールを作成します。

Parameters:
  LoggingAccountEmail:
    Type: String
    Description: The email Id for centralized logging account
  LoggingAccountName:
    Type: String
    Description: Name for centralized logging account
  SecurityAccountEmail:
    Type: String
    Description: The email Id for security roles account
  SecurityAccountName:
    Type: String
    Description: Name for security roles account
Resources:
  MyOrganization:
    Type: 'AWS::Organizations::Organization'
    Properties:
      FeatureSet: ALL
  LoggingAccount:
    Type: 'AWS::Organizations::Account'
    Properties:
      AccountName: !Ref LoggingAccountName
      Email: !Ref LoggingAccountEmail
  SecurityAccount:
    Type: 'AWS::Organizations::Account'
    Properties:
      AccountName: !Ref SecurityAccountName
      Email: !Ref SecurityAccountEmail
  AWSControlTowerAdmin:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: AWSControlTowerAdmin
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: controltower.amazonaws.com
            Action: 'sts:AssumeRole'
      Path: '/service-role/'
      ManagedPolicyArns:
        - !Sub >-
          arn:${AWS::Partition}:iam::aws:policy/service-role/AWSControlTowerServiceRolePolicy
  AWSControlTowerAdminPolicy:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: AWSControlTowerAdminPolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: 'ec2:DescribeAvailabilityZones'
            Resource: '*'
      Roles:
        - !Ref AWSControlTowerAdmin
  AWSControlTowerRMSPermissions:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: AWSControlTowerRMSPermissions
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - 'account:EnableRegion'
              - 'account:ListRegions'
              - 'account:GetRegionOptStatus'
            Resource: '*'
      Roles:
        - !Ref AWSControlTowerAdmin
  AWSControlTowerCloudTrailRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: AWSControlTowerCloudTrailRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: 'sts:AssumeRole'
      Path: '/service-role/'
  AWSControlTowerCloudTrailRolePolicy:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: AWSControlTowerCloudTrailRolePolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 'logs:CreateLogStream'
              - 'logs:PutLogEvents'
            Resource: !Sub >-
              arn:${AWS::Partition}:logs:*:*:log-group:aws-controltower/CloudTrailLogs:*
            Effect: Allow
      Roles:
        - !Ref AWSControlTowerCloudTrailRole
      Path: '/service-role/'
  AWSControlTowerConfigAggregatorRoleForOrganizations:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: AWSControlTowerConfigAggregatorRoleForOrganizations
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: 'sts:AssumeRole'
      Path: '/service-role/'
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSConfigRoleForOrganizations
  AWSControlTowerStackSetRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: AWSControlTowerStackSetRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action: 'sts:AssumeRole'
      Path: '/service-role/'
  AWSControlTowerStackSetRolePolicy:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: AWSControlTowerStackSetRolePolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action: 'sts:AssumeRole'
            Resource: !Sub 'arn:${AWS::Partition}:iam::*:role/AWSControlTowerExecution'
            Effect: Allow
      Roles:
        - !Ref AWSControlTowerStackSetRole

Outputs:
  LogAccountId:
    Value:
      Fn::GetAtt: LoggingAccount.AccountId
    Export:
      Name: LogAccountId
  SecurityAccountId:
    Value:
      Fn::GetAtt: SecurityAccount.AccountId
    Export:
      Name: SecurityAccountId

Prerequisites for launching a landing zone using AWS CloudFormation - AWS Control Tower

次に以下のCloudFormationを実行してランディングゾーンを作成します。

AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  Version:
    Type: String
    Default: "1.0.0"
    Description: The version number of Landing Zone
  GovernedRegions:
    Type: CommaDelimitedList
    Description: List of governed regions
  SecurityOuName:
    Type: String
    Description: The security Organizational Unit name
  SandboxOuName:
    Type: String
    Description: The sandbox Organizational Unit name
  CentralizedLoggingAccountId:
    Type: String
    Description: The AWS account ID for centralized logging
  SecurityAccountId:
    Type: String
    Description: The AWS account ID for security roles
  LoggingBucketRetentionPeriod:
    Type: Number
    Description: Retention period for centralized logging bucket
  AccessLoggingBucketRetentionPeriod:
    Type: Number
    Description: Retention period for access logging bucket

Resources:
  MyLandingZone:
    Type: AWS::ControlTower::LandingZone
    Properties:
      Version: !Ref Version
      Tags:
        - Key: "k1"
          Value: "v1b"
        - Key: "k3"
          Value: "v3"
      Manifest:
        GovernedRegions: !Join
          - ","
          - !Ref GovernedRegions
        OrganizationStructure:
          Security:
            Name: !Ref SecurityOuName
          Sandbox:
            Name: !Ref SandboxOuName
        CentralizedLogging:
          AccountId: !Ref CentralizedLoggingAccountId
          Configurations:
            LoggingBucket:
              RetentionDays: !Ref LoggingBucketRetentionPeriod
            AccessLoggingBucket:
              RetentionDays: !Ref AccessLoggingBucketRetentionPeriod
        SecurityRoles:
          AccountId: !Ref SecurityAccountId
        AccessManagement:
          Enabled: "false"

Create a new landing zone using AWS CloudFormation - AWS Control Tower

Stack作成の実行コマンドは以下のようになります。

aws cloudformation create-stack --stack-name ControlTower \
--template-body file://controltower.yml \
--parameters \
ParameterKey=Version,ParameterValue=3.2.0 \
ParameterKey=GovernedRegions,ParameterValue=ap-northest-1 \
ParameterKey=SecurityOuName,ParameterValue=Security \
ParameterKey=SandboxOuName,ParameterValue=Sandbox \
ParameterKey=CentralizedLoggingAccountId,ParameterValue=<log-accout-id> \
ParameterKey=SecurityAccountId,ParameterValue=<security-accout-id> \
ParameterKey=LoggingBucketRetentionPeriod,ParameterValue=3 \
ParameterKey=AccessLoggingBucketRetentionPeriod,ParameterValue=3 \
ParameterKey=KMSKey,ParameterValue=arn:aws:kms:ap-northeast-1:<management-accout-id>:key/<key-id>

ただ、作成されたStackは以下のようにFAILEDになってしまいました。

現時点の最新が3.2.0でしたが、エラーメッセージとしてLandingZone version must be latest available versionが返されてしまいました。
(ちなみにパラメータのドキュメントと同じ .0 を抜いた 3.2を渡すと今度はValidationExceptionになってしまいました...)

Configuration update management in AWS Control Tower - AWS Control Tower

こちらも執筆時点でCloudFormationのドキュメントが整備されていなかったので後日確認したいと思います。

最後に

いままでランディングゾーンの設定はコンソールをぽちぽちする必要がありましたが、APIから可能になることでより実装の自動化が可能になりました。

まだ、利用できる環境が整備されていなそうですが、近日更新されると思うので期待して待ちたいと思います。
再掲になりますが、以下のブログで検証しています。

以上、たかやま(@nyan_kotaroo)でした。