CloudTrailとEventBridgeルールを使って特定のIAMたちを管理したい

CloudTrailとEventBridgeルールを使って特定のIAMたちを管理したい

Clock Icon2025.02.18

こんにちは、せーのです。

今日は特定のIAMユーザーの作成や削除、また特定のアカウントからスイッチロールでやってくる特定IAMの管理をCloudTrailとEventBridgeを使って実装してみたいと思います。

想定していること

  • 外部のベンダーさんにシステム構築を発注している
  • プロジェクトの終了などのタイミングでIAMの整理が行われる
  • 後日監査の意味で入退場を把握したい

概要

IAMに関する操作は全てAPI操作なので、APIを蓄積してあるCloudTrailを使うのが一番です。
CloudTrailイベントはEventbridgeで引っ掛けることができますので、イベント内容を指定して、対象ユーザーを絞った上でルールとして設定すれば、リアルタイムにて検知することができます。

検知したイベントはSNSと連携してメールやSlackに飛ばしたり、Lambdaなどに飛ばして加工したり自由に処理することができます。

やるべきアーキテクチャはシンプルなのですが、検知すべき内容を調べるのが手間なんですよね。

手順

EventBridgeルールの作成

検知はEventbridgeの「ルール」を作成することで実現できます。
まずマネージメントコンソールよりEventbridgeのページに飛んで、左ペインの「ルール」をクリック、中央の「ルールを作成」ボタンから新規ルール作成画面に飛びます。

名前をつけます。ルールタイプは「イベントパターンを持つルール」です。

eventbridge_iam1

次にイベントパターンを作ります。
イベントソースは「AWSイベントまたはEventbridgeパートナーイベント」を選択します。

eventbridge_iam2

イベントパターンはカスタムにし、JSONにて直接検知したいパターンを書き込みます。

eventbridge_iam3

このJSONは色々なパターンが書けるので、後述します。

JSONが書き終わったらターゲットを決めます。
今回は通知される内容を把握するため、SNSでメールに飛ばしてみようと思います。
SNSのトピックは事前に作っておき、ここではトピック名を選択する形になります。

eventbridge_iam4

※参考
https://dev.classmethod.jp/articles/intor-subscribe-sns-with-email/

これでEventbridgeルールの完成です。ルールは後からでも修正できますので、JSONを色々書き換えてみましょう。

JSONルールを色々ためしてみる

IAMの作成、削除

まず最初にIAMの作成、削除を検知します。これはCloudTrailの「Createuser」「Deleteuser」を検知すればOKです。
JSONとしてはこうなります。

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["CreateUser", "DeleteUser"]
  }
}

ただ、これだと全てのIAMユーザーのCreate, Deleteを検知してしまうので、特定ユーザーに絞ってみます。

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["CreateUser", "DeleteUser"],
    "requestParameters": {
      "userName": ["cm-seinoIAM-test"]
    }
  }
}

こうするとcm-seinoIAM-testというIAMユーザーがCreate、Deleteされたりした時だけ、検知されます。

複数ユーザーの場合

一人だけ検知しても、なかなかシステム的な運用は厳しいです。JSONのうちIAMユーザー名を指定しているuserNameは配列形式になっているので、複数のユーザーを列記することができます。

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["CreateUser", "DeleteUser"],
    "requestParameters": {
      "userName": ["cm-seinoIAM-test", "cm-jinnoIAM-test"]
    }
  }
}

これでcm-seinoIAM-testcm-jinnoIAM-testという2つのIAMユーザーのCreate/Deleteを検知できるようになりました。

prefixとsuffix

対象の人が増えるたびにこのルールを書き換えていくのはなんだか面倒です。こんなときにはprefix(先頭の文字が一致)やsuffix(最後の文字が一致)を使ってみましょう。

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["CreateUser", "DeleteUser"],
    "requestParameters": {
      "userName": [{ "prefix": { "equals-ignore-case": "cm-" }}]
    }
  }
}

こう書くことで、cm-から始まるIAMユーザー全てを検知してくれます。
上の例ではequals-ignore-caseをつけることで大文字・小文字関係なく反応するようにしています。サービスです。

さて、先頭や最後の文字の一致で検出するにはもう一つ、wildcardという方法もあります。

{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": ["CreateUser", "DeleteUser"],
    "requestParameters": {
      "userName": [{ "wildcard": "cm-*" }]
    }
  }
}

このように書くことでprefixと同じ効果がでます。この書き方はこの後書くスイッチロールで役に立ちます。

入力トランスフォーマー

こうして検知したイベントをそのままSNSからメールに投げると、このようなメッセージとなります。

{
    "version": "0",
    "id": "********-****-****-****-************",
    "detail-type": "AWS API Call via CloudTrail",
    "source": "aws.iam",
    "account": "************",
    "time": "****-**-**T08:43:29Z",
    "region": "us-east-1",
    "resources": [],
    "detail": {
        "eventVersion": "1.10",
        "userIdentity": {
            "type": "AssumedRole",
            "principalId": "********************:cm-seino.tsuyoshi",
            "arn": "arn:aws:sts::************:assumed-role/cm-seino.tsuyoshi/cm-seino.tsuyoshi",
            "accountId": "************",
            "accessKeyId": "********************",
            "sessionContext": {
                "sessionIssuer": {
                    "type": "Role",
                    "principalId": "********************",
                    "arn": "arn:aws:iam::************:role/cm-seino.tsuyoshi",
                    "accountId": "************",
                    "userName": "cm-seino.tsuyoshi"
                },
                "attributes": {
                    "creationDate": "****-**-**T08:07:35Z",
                    "mfaAuthenticated": "true"
                }
            }
        },
        "eventTime": "****-**-**T08:43:29Z",
        "eventSource": "iam.amazonaws.com",
        "eventName": "CreateUser",
        "awsRegion": "us-east-1",
        "sourceIPAddress": "***.***.***.**",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
        "requestParameters": {
            "userName": "cm-seinoIAM-test"
        },
        "responseElements": {
            "user": {
                "path": "/",
                "userName": "cm-seinoIAM-test",
                "userId": "********************",
                "arn": "arn:aws:iam::************:user/cm-seinoIAM-test",
                "createDate": "****-**-** 8:43:29 AM"
            }
        },
        "requestID": "********-****-****-****-************",
        "eventID": "********-****-****-****-************",
        "readOnly": false,
        "eventType": "AwsApiCall",
        "managementEvent": true,
        "recipientAccountId": "************",
        "eventCategory": "Management",
        "tlsDetails": {
            "tlsVersion": "TLSv1.3",
            "cipherSuite": "TLS_AES_128_GCM_SHA256",
            "clientProvidedHostHeader": "iam.amazonaws.com"
        },
        "sessionCredentialFromConsole": "true"
    }
}

さすがCloudTrail、証跡ということでとても細かいのですが、細かすぎてよくわかりません。
今回欲しいのはCreate/Deleteの日時の対象のIAMユーザー名だけなので、その情報にフィルタリングしてみたいと思います。
ここでは「入力トランスフォーマー」という機能を使ってみましょう。

作成したEventbridgeルールを編集し、ターゲットの項目まで進めると、ターゲットの下に「追加設定」というトグルがありますので開きます。

eventbridge_iam4

ターゲット入力を「入力トランスフォーマー」とし、「入力トランスフォーマーを設定」ボタンをクリックします。

CleanShot 2025-02-17 at 19.09.06@2x

入力トランスフォーマーは「入力パス」と「テンプレート」、「出力」の欄に分かれています。
ターゲットへの入力としてきたJSON、今回で言えばCloudTrailから発出されたJSONのうち必要な項目を変数: JSONの値という形で「入力パス」にまとめます。今回必要なのは「いつ」「誰が」「何をした」なので、それぞれeventTime, username, eventNameの3つを同じ名前の変数としてまとめます。

CleanShot 2025-02-17 at 19.17.34@2x

次に「テンプレート」です。テンプレートは実際にターゲットに投げる際にどのような形にするか、を設定します。
例えばメールの文章のような形にしてもよいですし、後で処理をしやすい形を考えます。今回はCSVの形にしてみました。

CleanShot 2025-02-17 at 19.17.42@2x

最後に「出力」ですが、これは設定した入力パス、テンプレートがあっているかどうかをテストする項目です。
上の「サンプルイベント」という項目に実際に送られてくる元のJSON(今回でいえばCloudTrailからのJSON)をセットし、「出力を生成」ボタンを押すと、結果が「出力」に表示されます。

CleanShot 2025-02-17 at 19.18.51@2x

これで入力トランスフォーマーの設定は完了です。
この状態でcm-で始まるIAMユーザーが作成、削除されれば、CSVの形でメールが飛んでいく事になります。
ターゲットをLambdaにして、受け取ったCSVをファイルに書き込んでS3などに保存すればcm-のユーザー専用の入退場管理ができます。

スイッチロール

もう一つ、別アカウントにいるIAMユーザが管理しているアカウントにスイッチロールしてきた場合を検知してみましょう。JSONはこのようになります。

{
    "source": ["aws.signin"],
    "detail-type": ["AWS Console Sign In via CloudTrail"],
    "detail": {
      "eventSource": ["signin.amazonaws.com"],
      "eventName": ["SwitchRole"],
      "additionalEventData": {
        "SwitchFrom": ["arn:aws:iam::123456789012:user/cm-seino.tsuyoshi"]
      }
    }
  }

これで特定のアカウント123456789012からスイッチロールしてきた特定のユーザーcm-seino.tsuyoshiを検知できます。
SwitchFromとは「どこからスイッチロールしてきたのか」という情報で、arnの形で入ってきます。同じように「どこへ行くのか」というSwitchToという項目もありますが、今回必要なのは「どこからきたのか」なのでSwitchFromを検知対象にしています。

このSwitchFromの部分を先程ご紹介した「wildcard」を使って汎用化させてみましょう。

{
    "source": ["aws.signin"],
    "detail-type": ["AWS Console Sign In via CloudTrail"],
    "detail": {
        "eventSource": ["signin.amazonaws.com"],
        "eventName": ["SwitchRole"],
        "additionalEventData": {
          "SwitchFrom": [{ "wildcard": "*/cm-*" }]
      }
    }
  }

このようにするとcm-ではじまるユーザーがスイッチロールしたものが引っかかります。応用で特定のアカウントからスイッチロールしてきたユーザーを全て検知するなら、cm-の部分をアカウントIDに変えればOKです。

まとめ

CloudTrailにて特定IAMユーザーの作成、削除、特定アカウントからのスイッチロールなどをEventBridgeにて検知する方法をお知らせしました。
他にもCloudTrail Lakeを作成したり、S3バケットに保管されているCloudTrailデータに対してAthenaでクエリ検索する方法もあると思いますが、CloudTrail Lakeは保管されている期間に注意を払う必要がありますし、S3バケットの中にあるCloudTrailデータは大量なので、きちんとパーティショニングしないとコストが掛かる可能性があります。
今回ご紹介したこの方法ですと入退場とスイッチロールした時のみイベントが走りますので、必要最低限のコストで回せるかと思います。どうぞ参考にしてみてください。

参考リンク

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-create-pattern-operators.html
https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-create-rule.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.