2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IAM Identity Center ユーザーの S3 オブジェクト操作を Athena で追跡する

Last updated at Posted at 2025-05-01

はじめに

IAM Identity Center で SSO ログインしたユーザーの S3 オブジェクト操作をモニタリングしたい場合は、CloudTrail のデータべイベントの useridentity.principaliduseridentity.arn に着目する必要があります。

クエリ例
SELECT
    eventtime,
    useridentity.principalid,
    useridentity.arn,
    sourceipaddress,
    useragent,
    requestparameters
FROM cloudtrail_logs_pp
WHERE eventtime >= '2025-04-28T06:00:00Z' 
    AND eventname in ('GetObject','PutObject', 'DeleteObject', 'DeleteObjects')
    AND eventSource = 's3.amazonaws.com'
    AND useridentity.type = 'AssumedRole'
    AND useragent != 'athena.amazonaws.com';

CloudTrail イベントの useridentity エレメントの違い

以下のドキュメントに例が記載されています。

IAM ユーザーによる操作 ("type": "IAMUser")

userIdentity.userName に IAM ユーザー名が記録されます。

"userIdentity": {
    "type": "IAMUser",
    "principalId": "AIDAJ45Q7YFFAREXAMPLE",
    "arn": "arn:aws:iam::123456789012:user/Alice",
    "accountId": "123456789012",
    "accessKeyId": "",
    "userName": "Alice"
}

SSO ユーザーによる操作 ("type": "AssumedRole")

SSO ログインの場合には、内部的には STS による Assume Role でのアクセスになるため、username には値が記録されません。そのため、ロールセッション名を確認できる useridentity.principaliduseridentity.arn を参照します。

userIdentity.sessionContext.serssionIssuer で参照できる arn や userName はロール名のみが記録されるため、ユーザーまでは把握できません。

"userIdentity": {
    "type": "AssumedRole",
    "principalId": "AROAIDPPEZS35WEXAMPLE:AssumedRoleSessionName",
    "arn": "arn:aws:sts::123456789012:assumed-role/RoleToBeAssumed/MySessionName",
    "accountId": "123456789012",
    "accessKeyId": "",
    "sessionContext": {
        "sessionIssuer": {
            "type": "Role",
            "principalId": "AROAIDPPEZS35WEXAMPLE",
            "arn": "arn:aws:iam::123456789012:role/RoleToBeAssumed",
            "accountId": "123456789012",
            "userName": "RoleToBeAssumed"
        },
        "attributes": {
            "mfaAuthenticated": "false",
            "creationDate": "20131102T010628Z"
        }    
    }
}

参考: IAM Identity Center ユーザーに代わって行われたリクエスト ("type": "IdentityCenterUser")

"userIdentity": {
    "type": "IdentityCenterUser",
    "accountId": "123456789012",
    "onBehalfOf": {
        "userId": "544894e8-80c1-707f-60e3-3ba6510dfac1",
        "identityStoreArn": "arn:aws:identitystore::123456789012:identitystore/d-9067642ac7" 
    },
    "credentialId": "EXAMPLEVHULjJdTUdPJfofVa1sufHDoj7aYcOYcxFVllWR_Whr1fEXAMPLE"
}

このタイプのリクエストは IAM Identity Center を使用してアプリケーションアクセスを行った場合などに記録されます。例えば Amazon Q Developer (CodeWhisperer) の IDE によるアクティビティをデータイベントとして取得できますが、"type": "IdentityCenterUser" で記録されます。

AWS アカウントにアクセスしたユーザーの操作記録は前述のとおり "type": "AssumedRole" として記録されることにご注意ください。

また 2025/7/14 以降、アクセスポータルにおける操作など、これまで userIdentity が Unknown で記録されていたものも "type": "IdentityCenterUser" として記録されるように変更される予定です。

変更の対象:

このタイプのリクエストは userIdentity.onBehalfOf で IAM Identity Center ユーザーの userId を確認できるほか、additionalEventData 要素で userName も確認できるようです。

事前に必要な設定

S3 データイベントの取得設定

CloudTrail 証跡で S3 のオブジェクトレベルの操作を記録するにはデータイベントの記録を有効化する必要があります。

image.png

CloudTrail ログ用テーブルの作成

パーティション射影を使用して Athena で CloudTrail ログ用テーブルを作成します。必要に応じて専用のデータベースを作成し、ドキュメントに記載の CREATE TABLE ステートメントを実行するだけで OK です。

パーティション射影を使用することで、必要なパーティションのみを効率的にスキャンできるため、クエリの実行時間が短縮され、スキャンするデータ量が減ってコストも削減されます。

参考: S3 サーバーアクセスログ用テーブルの作成

CloudTrail のデータイベントでは DeleteObjects API などバッチオペレーション操作はオブジェクトキーやアクセス拒否 (Access Denied) などの情報が記録されません。必要に応じて S3 サーバーアクセスログを組み合わせて分析することも検討できます。S3 のサーバーアクセスログの出力はベストエフォートである点にはご注意ください。

パーティション射影を使用して S3 のサーバーアクセスログを分析する方法は以下のナレッジに記載があります。

サーバーアクセスログでパーティション射影を使用する場合はログオブジェクトキーの形式を「分析およびクエリのアプリケーションを高速化するには、この形式を使用します。」の方で選択する必要があります。

image.png

実行例

これまでの情報を踏まえて以下のようなクエリを実行してみます。このクエリでは S3 バケットへのアクセスパターンを分析したり、不正アクセスの調査をしたりすることを前提に、SSO ユーザーによる特定の S3 オブジェクト操作(取得、追加、削除)を抽出します。またアクセス拒否が発生したかどうかを示す access_denied フィールドを追加しています。

SELECT
    eventtime AS event_time,
    eventname AS event_name,
    awsRegion AS aws_region,
    json_extract_scalar(requestparameters, '$.bucketName') AS bucket_name,
    json_extract_scalar(requestparameters, '$.key') AS object_key,
    useridentity.principalId AS user_id,
    useridentity.arn AS user_arn,
    sourceipaddress AS source_ip,
    useragent AS user_agent,
    CASE 
        WHEN errorcode = 'AccessDenied' THEN 'Yes'
        ELSE 'No'
    END AS access_denied,
    errorcode AS error_code,
    errormessage AS error_message
FROM cloudtrail_logs_pp
WHERE eventtime >= '2025-04-30T06:00:00Z' 
    AND eventname in ('GetObject','PutObject', 'DeleteObject', 'DeleteObjects')
    AND eventSource = 's3.amazonaws.com'
    AND useridentity.type = 'AssumedRole'
    AND useragent NOT LIKE '%.amazonaws.com'  -- AWS サービスのユーザーエージェントを除外
ORDER BY eventtime ASC

以下のような実行結果を得ることができます。

image.png

肝心な情報が黒塗りばかりで恐縮ですが、テキストでマスキングすると以下のような結果です。

"event_time","event_name","aws_region","bucket_name","object_key","user_id","user_arn","source_ip","user_agent","access_denied","error_code","error_message"
"2025-04-30T16:28:12Z","GetObject","ap-northeast-1","<bucket_name>","test.json","PrincipalID:example@example.com","arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_ViewOnlyAccess_abcd1234efgh5678/example@example.com","xxx.xxx.xxx.xxx","[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36]","Yes","AccessDenied","User: arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_ViewOnlyAccess_abcd1234efgh5678/example@example.com is not authorized to perform: s3:GetObject on resource: ""arn:aws:s3:::<bucket_name>/test.json"" because no identity-based policy allows the s3:GetObject action"
"2025-04-30T16:28:32Z","DeleteObjects","ap-northeast-1","<bucket_name>",,"PrincipalID:example@example.com","arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_ViewOnlyAccess_abcd1234efgh5678/example@example.com","xxx.xxx.xxx.xxx","[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36]","No",,
"2025-04-30T17:31:33Z","DeleteObject","ap-northeast-1","<bucket_name>","test.json","PrincipalID:example@example.com","arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_ViewOnlyAccess_abcd1234efgh5678/example@example.com","xxx.xxx.xxx.xxx","[aws-cli/2.25.8 md/awscrt#0.23.8 ua/2.1 os/windows#10 md/arch#amd64 lang/python#3.12.9 md/pyimpl#CPython m/G cfg/retry-mode#standard md/installer#exe md/prompt#off md/command#s3.rm]","Yes","AccessDenied","User: arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_ViewOnlyAccess_abcd1234efgh5678/example@example.com is not authorized to perform: s3:DeleteObject on resource: ""arn:aws:s3:::<bucket_name>/test.json"" because no identity-based policy allows the s3:DeleteObject action"
"2025-05-01T01:26:03Z","PutObject","ap-northeast-1","<bucket_name>","test2.json","PrincipalID:example@example.com","arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_AdministratorAccess_wxyz9876ijkl4321/example@example.com","xxx.xxx.xxx.xxx","[aws-cli/2.26.6 md/awscrt#0.25.4 ua/2.1 os/linux#6.1.132-147.221.amzn2023.x86_64 md/arch#x86_64 lang/python#3.13.2 md/pyimpl#CPython exec-env/CloudShell m/G cfg/retry-mode#standard md/installer#exe md/distrib#amzn.2023 md/prompt#off md/command#s3.cp]","No",,

前述の S3 サーバーアクセスログを併用することで、DeleteObjects API によって削除が試行されたオブジェクトキーを特定することもできます。

WITH cloudtrail_events AS (
    SELECT
        eventtime AS event_time,
        eventname AS event_name,
        awsRegion AS aws_region,
        json_extract_scalar(requestparameters, '$.bucketName') AS bucket_name,
        json_extract_scalar(requestparameters, '$.key') AS object_key,
        useridentity.principalId AS user_id,
        useridentity.arn AS user_arn,
        sourceipaddress AS source_ip,
        useragent AS user_agent,
        CASE 
            WHEN errorcode = 'AccessDenied' THEN 'Yes'
            ELSE 'No'
        END AS access_denied,
        errorcode AS error_code,
        errormessage AS error_message,
        requestid AS request_id
    FROM cloudtrail_logs_pp
    WHERE eventtime >= '2025-05-01T00:00:00Z' 
        AND eventname = 'DeleteObjects'
        AND eventSource = 's3.amazonaws.com'
        AND useridentity.type = 'AssumedRole'
        AND useragent NOT LIKE '%.amazonaws.com'
),

s3_logs AS (
    SELECT
        parse_datetime(requestdatetime, 'dd/MMM/yyyy:HH:mm:ss Z') AS log_time,
        bucket_name,
        remoteip AS remote_ip,
        requester,
        operation,
        key AS object_key,
        httpstatus,
        errorcode AS s3_error_code,
        useragent AS s3_user_agent,
        requestid AS request_id
    FROM server_access_logs_pp
    WHERE timestamp >= '2025/05/01'
        AND operation = 'BATCH.DELETE.OBJECT'
)

-- CloudTrail データイベントと S3 サーバーアクセスログを結合
SELECT
    CASE 
        WHEN c.event_time IS NOT NULL THEN CAST(c.event_time AS varchar)
        ELSE CAST(s.log_time AS varchar)
    END AS operation_time,
    COALESCE(c.bucket_name, s.bucket_name) AS bucket_name,
    s.operation,
    COALESCE(c.object_key, s.object_key) AS object_key,
    c.user_arn,
    COALESCE(c.source_ip, s.remote_ip) AS source_ip,
    COALESCE(c.user_agent, s.s3_user_agent) AS user_agent,
    s.httpstatus,
    CASE 
        WHEN s.httpstatus = '403' OR c.access_denied = 'Yes' THEN 'Yes'
        ELSE 'No'
    END AS access_denied,
    COALESCE(c.error_code, s.s3_error_code) AS error_code,
    c.error_message,
    c.request_id
FROM cloudtrail_events c
FULL OUTER JOIN s3_logs s ON c.request_id = s.request_id
ORDER BY operation_time ASC

image.png

以上です。
参考になれば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?