AWSアカウントへのサインインやスイッチロールを検知してSlackに通知する

AWSアカウントへのサインインやスイッチロールをSlackに通知する仕組みをCloudFormationで作ってみました。
2023.03.13

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

AWSアカウントにサインインやスイッチロールしたことを通知する仕組みを作ってみるのはどうだろう?とふと思ったので、作ってみました。 画面ポチポチではなく、AWS CloudFormationでデプロイします。

おすすめの方

  • AWSにサインイン(スイッチロール含む)したとき、Slackに通知する仕組みを知りたい方
  • 上記をAWS CloudFormationで作成したい方
  • Amazon EventBridgeのAPI destinationsをCloudFormationで作成したい方

前提(大事なこと)

AWS CloudTrailを有効にする

サインインやスイッチロールは、AWS CloudTrailが検知します。 そのため、AWS CloudTrailを有効にしてください。

全リージョンにデプロイする

サインインが記録されるリージョンは、固定ではありません。 そのため、全リージョンにデプロイすることをおすすめします。 もしかしたら、他に良い方法があるかもしれません……。

なお、スイッチロールについては、該当のリージョンおよびバージニア北部(us-east-1)のそれぞれで記録されるようです。

AWSアクセスキーの利用は通知しない

今回の仕組みでは、AWSアクセスキーの利用は通知しません。 AWSアクセスキーの利用も通知したい場合は、下記などを参考にして、Amazon EventBridgeのルールを作成してください。

今回はAWS Chatbotを利用しない(情報が少ないため)

AWS ChatbotでもSlackに通知できますが、「情報が足りない」と思うかもしれません。

AWS Chatbotで通知された内容

具体的には、下記の情報(Amazon EventBridgeのサンプルイベント)がありますが、AWS Chatbotを利用した場合だと知りたいことが少ないと思うかもしれません。

{
  "version": "0",
  "id": "6f87d04b-9f74-4f04-a780-7acf4b0a9b38",
  "detail-type": "AWS Console Sign In via CloudTrail",
  "source": "aws.signin",
  "account": "123456789012",
  "time": "2016-01-05T18:21:27Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "eventVersion": "1.02",
    "userIdentity": {
      "type": "Root",
      "principalId": "123456789012",
      "arn": "arn:aws:iam::123456789012:root",
      "accountId": "123456789012"
    },
    "eventTime": "2016-01-05T18:21:27Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "ConsoleLogin",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "0.0.0.0",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
    "requestParameters": null,
    "responseElements": {
      "ConsoleLogin": "Success"
    },
    "additionalEventData": {
      "LoginTo": "https://console.aws.amazon.com/console/home?state=hashArgs%23&isauthcode=true",
      "MobileVersion": "No",
      "MFAUsed": "No"
    },
    "eventID": "324731c0-64b3-4421-b552-dfc3c27df4f6",
    "eventType": "AwsConsoleSignIn"
  }
}

そのため、本記事では、Amazon EventBridgeからSlackのIncoming WebhookにHTTPリクエストを行いました。

SlackのIncoming WebhookのURLを取得する

次のドキュメントを参考にして、Incoming WebhookのURLを取得します。

動作を確認しておきます。

curl -X POST -H "Content-type: application/json" \
-d '{"text": "Hello, world."}' \
"https://hooks.slack.com/services/aaa/bbb/ccc"

AWSアカウントへのサインインやスイッチロールを検知してSlackに通知する仕組みを作る

CloudFormationテンプレート

Amazon EventBridgeのルールを定義し、API destinationsでSlackに通知します。通知内容などは、必要に応じてカスタマイズしてください。

notify.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: Notify slack aws signin stack

Parameters:
  SlackIncomingWebhookUrl:
    Type: String

Resources:
  SigninEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.signin
        detail-type:
          - AWS Console Sign In via CloudTrail
        detail:
          eventSource:
            - signin.amazonaws.com
      Targets:
        - Id: NotifySlackSigninApiDestination
          Arn: !GetAtt NotifySlackSigninApiDestination.Arn
          RoleArn: !GetAtt NotifySlackSigninEventRuleRole.Arn
          InputTransformer:
            InputPathsMap:
              account: $.account
              eventTime: $.detail.eventTime
              eventName: $.detail.eventName
              eventID: $.detail.eventID
              userIdentityType: $.detail.userIdentity.type
              userIdentityArn: $.detail.userIdentity.arn
              LoginTo: $.detail.additionalEventData.LoginTo
              SwitchFrom: $.detail.additionalEventData.SwitchFrom
              SwitchTo: $.detail.additionalEventData.SwitchTo
            InputTemplate: >
              {
                "blocks": [
                  {
                    "type": "section",
                    "fields": [
                      {
                        "type": "mrkdwn",
                        "text": "*eventName:* <eventName>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*eventID:* <eventID>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*account:* <account>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*eventTime:* <eventTime>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*userIdentityType:* <userIdentityType>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*userIdentityArn:* <userIdentityArn>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*LoginTo:* <LoginTo>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*SwitchFrom:* <SwitchFrom>"
                      },
                      {
                        "type": "mrkdwn",
                        "text": "*SwitchTo:* <SwitchTo>"
                      }
                    ]
                  }
                ]
              }

  NotifySlackSigninEventRuleRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub notify-slack-signin-event-rule-${AWS::Region}-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: "deploy-iam-sample-deploy-policy-for-user"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: events:InvokeApiDestination
                Resource: !GetAtt NotifySlackSigninApiDestination.Arn

  NotifySlackSigninConnection:
    Type: AWS::Events::Connection
    Properties: 
      Name: notify-slack-signin-connection
      AuthorizationType: API_KEY
      AuthParameters: 
        ApiKeyAuthParameters:
          ApiKeyName: dummy
          ApiKeyValue: dummy

  NotifySlackSigninApiDestination:
    Type: AWS::Events::ApiDestination
    Properties:
      Name: notify-slack-signin-api-destination
      ConnectionArn: !GetAtt NotifySlackSigninConnection.Arn
      HttpMethod: POST
      InvocationEndpoint: !Ref SlackIncomingWebhookUrl

デプロイ

リージョン(us-east-1)とパラメータを指定します。 SlackIncomingWebhookUrlには、SlackのIncoming WebhookのURLを指定します。

aws cloudformation deploy \
    --template-file notify.yaml \
    --stack-name notify-slack-aws-signin-chatbot-stack \
    --capabilities CAPABILITY_NAMED_IAM \
    --region us-east-1 \
    --parameter-overrides \
        SlackIncomingWebhookUrl="https://hooks.slack.com/services/xxx/yyy/zzz" \
    --no-fail-on-empty-changeset

動作確認する

IAMユーザの動作確認は、別途、ap-southeast-2にデプロイして確認しています。

なお、Slackアプリ名が「CircleCI」になっていますが、本実験用に「既存の実験用Slackアプリ(名前:CircelCI)」を利用したためです。気にしないでくださいませ。

サインイン(IMAユーザ)

Slackに通知された(サインイン)

スイッチロール(IAMロール)

Slackに通知された(スイッチロール)

スイッチバック(IAMロール)

Slackに通知された(スイッチバック)

さいごに

AWSアカウントへのサインインやスイッチロールをSlackに通知する仕組みをCloudFormationで作ってみました。 具体的な運用ルールなどを設ける必要はありますが、明らかに怪しいアクセス(土日祝など)には気づけると思います。

参考