概要
IAMを変更できる管理者ロールを使用した際に、通知が行く仕組みを作成したい
リージョン横断の具体的な実装の参考があまりなかったのでまとめておく
要約
-
CloudTrail のコンソールサインイン系イベント(
AWS Console Sign In via CloudTrail)はリージョンごとに発火する。1 リージョンだけ監視しても、別リージョンでの操作は素通りする - 解決策は 集約先リージョンにカスタム EventBus を 1 つ立て、各リージョンの EventBridge ルールから
PutEventsで寄せる こと - 寄せたイベントは中央側のルールで SNS → AWS Chatbot → Slack に流し、
SwitchRoleのうち管理者相当のロール名にマッチしたものだけを通知する - 全リージョン展開は CloudFormation StackSets で 1 アクションで済む
なぜ「リージョン横断」が必要か
AWS マネジメントコンソールにサインインしたり SwitchRole したりすると、CloudTrail に以下のようなイベントが残る。
{
"source": "aws.signin",
"detail-type": "AWS Console Sign In via CloudTrail",
"detail": {
"eventSource": "signin.amazonaws.com",
"eventName": "SwitchRole",
"additionalEventData": {
"SwitchTo": "arn:aws:iam::123456789012:role/ExampleAdminRole"
}
}
}
これは 発生したリージョンの EventBridge 既定バス に届く。たとえばユーザーが ap-northeast-1 のコンソールで SwitchRole したら、そのイベントは ap-northeast-1 の EventBridge にしか出ない。us-east-1 で待ち構えていても気づけない
「全リージョン分のルールと SNS と Chatbot 連携を 30 リージョン分作るのか…?」となるところを、集約用カスタム EventBus を 1 つ立てて寄せる ことで、通知ロジックは 1 箇所に集約できる
実装ポイント
1. カスタム EventBus とバスポリシー(中央側)
カスタム EventBus を作成し、同一アカウントの全リージョンから PutEvents を許可 するバスポリシーを付ける。Principal をアカウント root にすることで、別リージョンからの API コールに対しても効く。
CentralSignInBus:
Type: AWS::Events::EventBus
Properties:
Name: cloudtrail-central
CentralSignInBusPolicy:
Type: AWS::Events::EventBusPolicy
Properties:
EventBusName: !Ref CentralSignInBus
StatementId: AllowSameAccountCrossRegionPutEvents
Statement:
Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: events:PutEvents
Resource: !GetAtt CentralSignInBus.Arn
2. 転送用 IAM ロール(中央側で 1 つだけ作る)
IAM ロールはグローバルリソースなので、中央スタックで 1 つ作って、その ARN を各リージョンのルールに渡し回すのが楽。各リージョンで重複作成しなくて良い。
ForwarderRole:
Type: AWS::IAM::Role
Properties:
RoleName: EventBridgeSignInForwardToCentralRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: PutEventsToCentralSignInBus
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: events:PutEvents
Resource: !GetAtt CentralSignInBus.Arn
3. 各リージョンの転送ルール(StackSet 側)
各リージョンの default バス に対してルールを置き、ターゲットを 中央リージョンの カスタム EventBus ARN、RoleArn を ForwarderRole にする。
SwitchRoleForwardRule:
Type: AWS::Events::Rule
Properties:
Name: !Sub 'CloudTrailSignInSwitchRoleForward-${AWS::Region}'
EventPattern:
source: [aws.signin]
detail-type: ['AWS Console Sign In via CloudTrail']
detail:
eventSource: [signin.amazonaws.com]
eventName: [SwitchRole]
additionalEventData:
SwitchTo:
- wildcard: !Sub 'arn:aws:iam::*:role/*${RoleNameSubstring}*'
Targets:
- Id: CentralCustomEventBus
Arn: !Sub 'arn:aws:events:${CentralRegion}:${AWS::AccountId}:event-bus/${CentralEventBusName}'
RoleArn: !Ref ForwarderRoleArn
4. 中央側の通知ルール(SNS → Chatbot → Slack)
中央 EventBus に届いたイベントを SNS に流す。InputTransformer で Slack に読みやすい形式に整形しておくと、流れた瞬間に内容が把握できる。
Targets:
- Id: SignInAlertTopic
Arn: !Ref SignInAlertTopic
InputTransformer:
InputPathsMap:
AccountID: $.detail.userIdentity.accountId
AwsRegion: $.detail.awsRegion
EventTime: $.detail.eventTime
SwitchTo: $.detail.additionalEventData.SwitchTo
UserArn: $.detail.userIdentity.arn
InputTemplate: |
{
"version": "1.0",
"source": "custom",
"content": {
"textType": "client-markdown",
"title": ":bell: 管理者ロールへのスイッチを検知",
"description": "---------------------",
"nextSteps": [
"アカウントID: <AccountID>",
"リージョン: <AwsRegion>",
"発生時刻: <EventTime>",
"ユーザーArn: <UserArn>",
"スイッチ先: <SwitchTo>"
]
},
"UserArn": "<UserArn>"
}
Slack 側ではこのように届く(イメージ):
🔔 管理者ロールへのスイッチを検知
---------------------
• アカウントID: 123456789012
• リージョン: ap-northeast-1
• 発生時刻: 2026-05-20T12:34:56Z
• ユーザーArn: arn:aws:iam::123456789012:user/example-user
• スイッチ先: arn:aws:iam::123456789012:role/ExampleAdminRole
さいごに
StackSetでの実行を知らないと「全リージョン分リソース作るのか。。。?」となりそうだったのでまとめました
誰かの助けになれば幸いです