Organizations、ControlTowerでアカウントが作成されたことを通知してみた

2024.03.27

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

Organizationsを運用している環境でアカウント発行者とアカウント利用者が別れていることがあります。

このような場合に、アカウント発行後にアカウント利用者側で後続作業を行うために、アカウントが作成されたことを知りたいというニーズがあるかと思います。

今回はアカウント発行後にアカウント利用者側で気付けるように、OrganizationsとControlTowerでアカウントが発行された際にSlackへ通知する方法をご紹介します。

さきにポイント

  • Organizationsのアカウント発行イベントはus-east-1(バージニア北部)で記録される
    • アカウント発行イベント名は CreateAccount
    • ControlTowerによるアカウント発行でもトリガーされるため、principalIdで判断する
  • ControlTowerのアカウント発行イベントはホームリージョンで記録される
    • アカウント発行イベント名は CreateManagedAccount

構成図

今回の検証ではControlTowerをap-northeast-1に設定しています。

やってみた

通知に必要なEventBridge、SNS、Chatbotは、CloudFormationで作成します。

ControlTowerの通知リソース作成

はじめにControlTowerのイベントを通知するためにホームリージョンでリソースを作成します。
ControlTowerはap-northeast-1をホームリージョンとしています。

AWSTemplateFormatVersion: "2010-09-09"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: ""
        Parameters:
          - ProjectName
          - Environment
    ParameterLabels: {}
Parameters:
  ProjectName:
    Type: String
    ConstraintDescription: This parameter is required.
    Description: The name of the project.
    MinLength: 1
  Environment:
    Type: String
    ConstraintDescription: This parameter is required.
    Description: The name of the environment.
    MinLength: 1
Resources:
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: !Sub "${ProjectName}-${Environment}-sns"
      TopicName: !Sub "${ProjectName}-${Environment}-sns"

  SnsTopicPolicy:
    Type: "AWS::SNS::TopicPolicy"
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Id: "__default_policy_ID"
        Statement:
          - Sid: "__default_statement_ID"
            Effect: "Allow"
            Principal:
              AWS: "*"
            Action:
              - "SNS:GetTopicAttributes"
              - "SNS:SetTopicAttributes"
              - "SNS:AddPermission"
              - "SNS:RemovePermission"
              - "SNS:DeleteTopic"
              - "SNS:Subscribe"
              - "SNS:ListSubscriptionsByTopic"
              - "SNS:Publish"
            Resource: !Ref SnsTopic
            Condition:
              StringEquals:
                "AWS:SourceOwner": !Sub ${AWS::AccountId}
          - Sid: "AWSEvents_Allow"
            Effect: "Allow"
            Principal:
              Service: "events.amazonaws.com"
            Action: "sns:Publish"
            Resource: !Ref SnsTopic
      Topics:
        - !Ref SnsTopic

  EventBridgeRuleControlTower:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub "${ProjectName}-${Environment}-controltower-events"
      Description: "EventBridge Rule for AWS Control Tower events"
      EventPattern:
        source:
          - "aws.controltower"
        detail-type:
          - "AWS Service Event via CloudTrail"
        detail:
          eventName:
            - "CreateManagedAccount"
      State: "ENABLED"
      Targets:
        - Arn: !Ref SnsTopic
          Id: "TargetSnsTopicCT"

Outputs:
  SnsTopicArn:
    Description: "The ARN of the SNS topic."
    Value: !Ref SnsTopic

CloudFormation作成後、出力でSNS TopicのARNが表示されます。
こちらは後続のOrganizations向けの通知テンプレート作成で使用するので控えます。

また、作成されたEventBridgeのRuleは以下のようになります。

{
  "detail-type": ["AWS Service Event via CloudTrail"],
  "source": ["aws.controltower"],
  "detail": {
    "eventName": ["CreateManagedAccount"]
  }
}

Account Factory を使用したアカウント作成の場合、CreateManagedAccountでトリガーされます。 AWS Control Tower でのライフサイクルイベント(CreateManagedAccount) - AWS Control Tower

Organizationsの通知リソース作成

次にOrganizationsのイベントを通知するためのリソースを作成していきます。
Organizationsのイベントはus-east-1(バージニア北部)でのみ記録されます。そのためOrganizationsのイベントを通知するリソースはus-east-1(バージニア北部)でリソースを作成していく必要があります。

重要
AWS Organizations の CloudTrail に関するすべての情報は、米国東部 (バージニア北部) リージョンのみで表示できます。CloudTrail コンソールで AWS Organizations アクティビティが表示されない場合は、右上隅のメニューを使用して、コンソールを 米国東部 (バージニア北部) に設定します。AWS CLI または SDK ツールを使用して CloudTrail のクエリを実行する場合、クエリを米国東部 (バージニア北部) エンドポイントに指定します。

AWS Organizations でのログ記録とモニタリング - AWS Organizations

テンプレートでは以下のパラメータを指定する必要があります。

  • ProjectName : 任意のプロジェクト名
  • Environment : 任意の環境名
  • SlackWorkspaceId : 事前に用意しているSlackのWorkspace ID
  • SlackChannelName : 任意のSlackのChannel Id
  • SNSTopicArn : 先ほど作成したControlTowerのSNS TopicのARN
AWSTemplateFormatVersion: "2010-09-09"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: ""
        Parameters:
          - ProjectName
          - Environment
          - SlackWorkspaceId
          - SlackChannelName
          - SNSTopicArn
    ParameterLabels: {}

Parameters:
  ProjectName:
    Type: String
    ConstraintDescription: This parameter is required.
    Description: The name of the project.
    MinLength: 1
  Environment:
    Type: String
    ConstraintDescription: This parameter is required.
    Description: The name of the environment.
    MinLength: 1
  SlackWorkspaceId:
    Type: String
    Default: ""
    Description: Slack Workspace ID
  SlackChannelName:
    Type: String
    Default: ""
    Description: Slack Channel Name
  SNSTopicArn:
    Type: String
    Description: The ARN of the SNS topic.
    MinLength: 1

Resources:
  SnsTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: !Sub "${ProjectName}-${Environment}-sns"
      TopicName: !Sub "${ProjectName}-${Environment}-sns"

  SnsTopicPolicy:
    Type: "AWS::SNS::TopicPolicy"
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Id: "__default_policy_ID"
        Statement:
          - Sid: "__default_statement_ID"
            Effect: "Allow"
            Principal:
              AWS: "*"
            Action:
              - "SNS:GetTopicAttributes"
              - "SNS:SetTopicAttributes"
              - "SNS:AddPermission"
              - "SNS:RemovePermission"
              - "SNS:DeleteTopic"
              - "SNS:Subscribe"
              - "SNS:ListSubscriptionsByTopic"
              - "SNS:Publish"
            Resource: !Ref SnsTopic
            Condition:
              StringEquals:
                "AWS:SourceOwner": !Sub ${AWS::AccountId}
          - Sid: "AWSEvents_Allow"
            Effect: "Allow"
            Principal:
              Service: "events.amazonaws.com"
            Action: "sns:Publish"
            Resource: !Ref SnsTopic
      Topics:
        - !Ref SnsTopic

  EventBridgeRuleOrganizations:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub "${ProjectName}-${Environment}-organization-events"
      Description: "EventBridge Rule for AWS Organizations events"
      EventPattern:
        source:
          - "aws.organizations"
        detail-type:
          - "AWS API Call via CloudTrail"
        detail:
          eventName:
            - "CreateAccount"
          userIdentity:
            principalId:
              - anything-but:
                  suffix: "CreateManagedAccount"
      State: "ENABLED"
      Targets:
        - Arn: !Ref SnsTopic
          Id: "TargetSnsTopicOrg"

  ChatBotConfigurationRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${ProjectName}-${Environment}-chatbot-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "chatbot.amazonaws.com"
            Action: "sts:AssumeRole"

  ChatBot:
    Type: AWS::Chatbot::SlackChannelConfiguration
    Properties:
      ConfigurationName: !Sub "${ProjectName}-${Environment}-chatbot"
      IamRoleArn: !GetAtt ChatBotConfigurationRole.Arn
      SlackChannelId: !Ref SlackChannelName
      SlackWorkspaceId: !Ref SlackWorkspaceId
      SnsTopicArns:
        - !Ref SnsTopic
        - !Ref SNSTopicArn

こちらで作成されたEventBridgeのRuleは以下のようになります。

{
  "detail-type": ["AWS API Call via CloudTrail"],
  "source": ["aws.organizations"],
  "detail": {
    "eventName": ["CreateAccount"],
    "userIdentity": {
      "principalId": [{
        "anything-but": {
          "suffix": "CreateManagedAccount"
        }
      }]
    }
  }
}

Organizationsのアカウント作成イベントはCreateAccountでトリガーされます。
ただこちらのイベントはControlTowerによるアカウント作成でもトリガーされるため、principalIdでControlTowerによる呼び出しかユーザによる呼び出しかを判断しています。

ちなみに、バックグラウンドワークフローが正常に完了した際に発行されるCreateAccountResultイベントもありますが、こちらはOrganizations/ControlTower両方の処理でトリガーされ判別が難しかったため通知のトリガーには使用していません。Organizationsでのみアカウントを発行している環境であれば、CreateAccountResultイベントを使用するのが良いかと思います。

通知を確認する

Organizationsからアカウントを作成します。

作成したあとのSlack通知がこちらです。
作成されたアカウントについての情報はありませんが、CreateAccountイベントからOrganizationsによるアカウント作成であることがわかります。

次にControlTowerのAccountFactoryからアカウントを作成します。

作成したあとのSlack通知がこちらです。
ControlTowerの通知では作成されたアカウントの名前や配置されたOU情報が含まれており内容がすこしリッチになっています。

最後に

今回、OrganizationsとControlTowerでアカウントが作成された際にSlackに通知する方法をご紹介しました。

アカウント発行者とアカウント利用者が別々の場合でも、アカウントが作成されたことを通知することで、アカウント利用者がアカウントを利用できるようになるまでのスピードを向上させることができるかと思います。

こちらの内容が誰かの助けになれば幸いです。

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