直近 90 日の操作なら、CloudTrail の「イベント履歴」を aws cloudtrail lookup-events で検索すれば、誰が・いつ・どこから操作したかが分かります。 イベント履歴は、設定なしで記録されていて、見るのに CloudTrail の料金はかかりません。

90 日より前の操作や、S3 のオブジェクトの読み書き(データイベント)を調べるには、前もって「証跡(trail)」で S3 にログを保存し、Athena で SQL を使って検索します。

調べたいこと 方法 条件
直近 90 日の管理イベント(作成・削除・設定変更・ログイン) aws cloudtrail lookup-events 1 回に1リージョン・条件は1つ
90 日より前の操作 証跡+Athena 証跡を作った後の分だけ
S3 のオブジェクト操作・Lambda の呼び出し(データイベント) 証跡(データイベントを有効)+Athena 有効にした後の分だけ。有料
複数の条件・複数リージョンをまとめて Athena(または CloudTrail Lake) 同上
例:知りたいこと lookup-events の条件
S3 バケットを誰が消したか AttributeKey=EventName,AttributeValue=DeleteBucket
IAM の権限を誰が変えたか AttributeKey=EventSource,AttributeValue=iam.amazonaws.com(us-east-1 で検索)
コンソールへのログイン履歴 AttributeKey=EventName,AttributeValue=ConsoleLogin
特定のユーザーの操作 AttributeKey=Username,AttributeValue=taro
特定のリソースへの操作 AttributeKey=ResourceName,AttributeValue=リソース名

確認環境:AWS CLI 1.46.1・jq(Linux)。moto 5.2.4 は LookupEvents に対応していなかったため、CloudTrail の LookupEvents API と同じ形の応答を返すサーバーを手元に用意し、ドキュメントにあるイベントの形(userIdentity などの項目)で応答を作りました。そのうえで、CLI が送るリクエスト、--query・jq での整形、ページ送りを確かめています。証跡(trail)の作成・バケットポリシー・Athena の start-query-execution は moto のサーバーモードで通ることを確かめました。Athena のテーブル定義とクエリ、イベントの記録のされ方、料金は AWS のドキュメントに基づいて書いています(確認日 2026年10月12日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CloudTrailで誰が操作したか調べる|lookup-eventsとAthena」

lookup-events の基本

aws cloudtrail lookup-events \
  --region ap-northeast-1 \
  --lookup-attributes AttributeKey=EventName,AttributeValue=DeleteBucket \
  --start-time 2026-10-01T00:00:00+09:00 \
  --end-time   2026-10-13T00:00:00+09:00
決まり 内容(ドキュメント)
期間 直近 90 日まで
対象 管理イベント(と CloudTrail Insights のイベント)。データイベントは入らない
リージョン 1 回の検索で 1 つのリージョンだけ。--region で指定する
条件 --lookup-attributes は1つだけ。ほかは時刻の範囲だけ
件数 1 回の応答で最大 50 件(既定 50)。続きは NextToken
速さの上限 アカウント・リージョンごとに 1 秒に 2 回
料金 イベント履歴を見るのは無料

--lookup-attributes の AttributeKey に使える値です。

AttributeKey 意味 例
EventName API の名前 DeleteBucket・TerminateInstances・ConsoleLogin
EventSource サービス s3.amazonaws.com・iam.amazonaws.com
Username 操作した人(IAM ユーザー名・ロールのセッション名など) taro
ResourceName リソース名・ID my-bucket・i-0123456789abcdef0
ResourceType リソースの種類 AWS::S3::Bucket・AWS::EC2::Instance
AccessKeyId 使われたアクセスキー AKIAIOSFODNN7EXAMPLE
ReadOnly 読み取り操作か false(変更だけ)
EventId イベントの ID —

--lookup-attributes に2つ書くと、CLI はそのまま2つを送ります(手元のサーバーで、リクエストに2つ入っていることを確かめました)。API の決まりでは1つだけなので、2つ目の条件は jq で絞ります(後述)。

IAM・STS・CloudFront の操作は us-east-1 にある

ドキュメントでは、IAM・STS・CloudFront のようなグローバルサービスのイベントは、多くが 米国東部(バージニア北部)= us-east-1 で記録されます。東京リージョンで lookup-events しても、IAM の権限変更は出てきません。 --region us-east-1 を付けて検索します。

コンソールへのログイン(ConsoleLogin)も、記録されるリージョンが決まっています。

ログインのしかた 記録されるリージョン(ドキュメント)
ルートユーザー us-east-1・us-east-2・us-west-2 のいずれか
IAM ユーザー(グローバルのサインイン、アカウントエイリアスの Cookie あり) us-east-2・eu-north-1・ap-southeast-2 のいずれか
IAM ユーザー(グローバルのサインイン、Cookie なし) us-east-1
IAM ユーザー(リージョンのエンドポイント) そのエンドポイントのリージョン

ログイン履歴を漏れなく見るには、複数のリージョンを順に検索します。

for r in us-east-1 us-east-2 us-west-2 eu-north-1 ap-southeast-2 ap-northeast-1; do
  echo "== $r"
  aws cloudtrail lookup-events --region "$r" \
    --lookup-attributes AttributeKey=EventName,AttributeValue=ConsoleLogin \
    --start-time "$(date -d '30 days ago' +%F)" \
    --output json \
  | jq -r '.Events[].CloudTrailEvent | fromjson
           | [.eventTime, .userIdentity.type, (.userIdentity.userName // .userIdentity.arn),
              .sourceIPAddress, .responseElements.ConsoleLogin, .additionalEventData.MFAUsed] | @tsv'
done

目的別コマンド集

誰が消したか

消えたもの EventName EventSource
S3 バケット DeleteBucket s3.amazonaws.com
EC2 インスタンス TerminateInstances ec2.amazonaws.com
EBS ボリューム・スナップショット DeleteVolume・DeleteSnapshot ec2.amazonaws.com
RDS インスタンス DeleteDBInstance rds.amazonaws.com
DynamoDB テーブル DeleteTable dynamodb.amazonaws.com
セキュリティグループのルール RevokeSecurityGroupIngress ec2.amazonaws.com
IAM ユーザー・ロール DeleteUser・DeleteRole(us-east-1) iam.amazonaws.com

S3 のオブジェクト(ファイル)の削除 DeleteObject はデータイベントなので、イベント履歴には出ません。 証跡でデータイベントを有効にしていた場合だけ、Athena で探せます。

リソース名が分かっているなら、ResourceName で探すのが確実です。

aws cloudtrail lookup-events --region ap-northeast-1 \
  --lookup-attributes AttributeKey=ResourceName,AttributeValue=my-old-bucket \
  --output json \
| jq '.Events[] | .CloudTrailEvent | fromjson
      | {time: .eventTime, event: .eventName, who: .userIdentity.arn,
         role: .userIdentity.sessionContext.sessionIssuer.userName,
         ip: .sourceIPAddress, key: .userIdentity.accessKeyId}'

手元のサーバーで、ロールを引き受けた(AssumedRole)利用者がバケットを消したイベントを返したときの出力です(アクセスキーなどはドキュメントの例の値)。

{
  "time": "2026-10-12T01:23:45Z",
  "event": "DeleteBucket",
  "who": "arn:aws:sts::123456789012:assumed-role/DevRole/hanako",
  "role": "DevRole",
  "ip": "203.0.113.10",
  "key": "ASIAIOSFODNN7EXAMPLE"
}

誰が権限を変えたか(IAM)

aws cloudtrail lookup-events --region us-east-1 \
  --lookup-attributes AttributeKey=EventSource,AttributeValue=iam.amazonaws.com \
  --start-time "$(date -d '14 days ago' +%F)" \
  --output json \
| jq -r '.Events[].CloudTrailEvent | fromjson
         | select(.readOnly == false)
         | select(.eventName | test("^(Attach|Detach|Put|Delete)(User|Role|Group)Policy$|^CreatePolicyVersion$|^SetDefaultPolicyVersion$|^UpdateAssumeRolePolicy$|^AddUserToGroup$|^CreateAccessKey$|^CreateLoginProfile$"))
         | [.eventTime, .eventName, .userIdentity.arn,
            (.requestParameters.roleName // .requestParameters.userName // .requestParameters.groupName // "-"),
            (.requestParameters.policyArn // .requestParameters.policyName // "-")] | @tsv'
EventName 意味
AttachRolePolicy・AttachUserPolicy・AttachGroupPolicy 管理ポリシーを付けた
PutRolePolicy・PutUserPolicy・PutGroupPolicy インラインポリシーを付けた・変えた
CreatePolicyVersion・SetDefaultPolicyVersion 管理ポリシーの中身を変えた
UpdateAssumeRolePolicy ロールの信頼ポリシーを変えた(誰が引き受けられるか)
AddUserToGroup グループに入れた(グループの権限が付く)
CreateAccessKey・CreateLoginProfile アクセスキー・コンソールのパスワードを作った

ポリシーの種類の違いは、関連記事「IAM管理ポリシーとインラインポリシーの違い|CLIで確認・アタッチ」で扱っています。

特定のユーザーの操作(変更だけ)

aws cloudtrail lookup-events --region ap-northeast-1 \
  --lookup-attributes AttributeKey=Username,AttributeValue=taro \
  --query 'Events[].[EventTime,EventName,Resources[0].ResourceName]' \
  --output text

変更の操作だけに絞るなら、ReadOnly=false で検索し、jq でユーザーを絞ります(条件は1つしか送れないため)。

aws cloudtrail lookup-events --region ap-northeast-1 \
  --lookup-attributes AttributeKey=ReadOnly,AttributeValue=false \
  --start-time "$(date -d '1 day ago' +%FT%T)" \
  --output json \
| jq -r '.Events[] | select(.Username == "taro")
         | [.EventName, (.Resources[0].ResourceName // "-")] | @tsv'

アクセスキーが漏れたとき:そのキーで何をされたか

aws cloudtrail lookup-events --region ap-northeast-1 \
  --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAIOSFODNN7EXAMPLE \
  --output json \
| jq -r '.Events[].CloudTrailEvent | fromjson
         | [.eventTime, .awsRegion, .eventName, .sourceIPAddress, (.errorCode // "OK")] | @tsv'

リージョンごとに記録されるので、使っていないリージョンも含めて全部を検索します。 リージョンの一覧は aws ec2 describe-regions --query 'Regions[].RegionName' --output text で取れます。アクセスキーの無効化とローテーションは、関連記事「IAMアクセスキーの作成・確認・ローテーション手順 CLI版」で扱っています。

出力の読み方

lookup-events の応答は、Events の配列です。

項目 意味
EventId イベントの ID
EventName API の名前
EventTime 発生時刻
EventSource サービス(s3.amazonaws.com など)
Username 操作した人の名前(ロールならセッション名)
Resources 対象のリソース(ResourceType・ResourceName)
AccessKeyId 使われたアクセスキー
ReadOnly 読み取りか("true"・"false" の文字列)
CloudTrailEvent イベントの全体。JSON が「文字列」として入っている

詳しい情報は CloudTrailEvent の中にあります。 文字列なので、jq の fromjson で JSON に戻してから読みます。--query(JMESPath)では、この文字列の中は読めません。

CloudTrailEvent の主な項目

項目 意味 調査での見方
userIdentity 誰が(種類・ARN・アクセスキーなど) 下の表
eventTime いつ(UTC、ISO 8601) 日本時間は +9 時間
eventSource・eventName 何を —
awsRegion どのリージョンで —
sourceIPAddress どこから(IP アドレス) AWS のサービスが代わりに呼んだときは、サービス名が入ることがある
userAgent 何を使って(コンソール・CLI・SDK) aws-cli/...・Boto3/... など
requestParameters 送られたパラメータ 消したバケット名・付けたポリシーの ARN など
responseElements 返った結果 ConsoleLogin: Success/Failure など
errorCode・errorMessage 失敗した理由 AccessDenied など。失敗した操作も記録される
readOnly 読み取りか 変更だけを見るなら false
recipientAccountId 記録したアカウント 他のアカウントからの操作の確認

userIdentity の type ごとの「誰か」

userIdentity.type 意味(ドキュメント) 人を特定する項目
Root ルートユーザー arn(...:root)
IAMUser IAM ユーザーの認証情報 userName・arn・accessKeyId
AssumedRole ロールを引き受けた一時的な認証情報 arn の最後(セッション名)、sessionContext.sessionIssuer.userName(ロール名)、sessionContext.sourceIdentity
IdentityCenterUser IAM Identity Center のユーザーの代わりに行った操作 onBehalfOf.userId・onBehalfOf.identityStoreArn
FederatedUser GetFederationToken の一時的な認証情報 principalId・arn
AWSService AWS のサービスが行った操作 invokedBy
AWSAccount 別のアカウントからの操作 accountId

AssumedRole のイベントには、人の名前が直接は入りません。 ARN の最後のセッション名(例 arn:aws:sts::123456789012:assumed-role/DevRole/hanako の hanako)や、sourceIdentity を設定していればその値で人をたどります。ロールの仕組みは、関連記事「IAMロールとは|ユーザー・ポリシーとの違いとAssumeRole、信頼ポリシー」で扱っています。

ドキュメントにあるコンソールログイン失敗のイベント(一部)です。

{
    "userIdentity": {
        "type": "IAMUser",
        "accountId": "123456789012",
        "accessKeyId": "",
        "userName": "Paulo"
    },
    "eventSource": "signin.amazonaws.com",
    "eventName": "ConsoleLogin",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "192.0.2.0",
    "errorMessage": "Failed authentication",
    "responseElements": {
        "ConsoleLogin": "Failure"
    },
    "additionalEventData": {
        "MobileVersion": "No",
        "MFAUsed": "Yes"
    },
    "eventType": "AwsConsoleSignIn",
    "eventCategory": "Management"
}

jq で一覧にする

手元のサーバーで、3件のイベント(ドキュメントの形で作成)を返したときの出力です。

aws cloudtrail lookup-events --output json \
| jq -r '.Events[] | .CloudTrailEvent | fromjson
         | [.eventTime, .eventName, .userIdentity.type, .userIdentity.arn, .sourceIPAddress] | @tsv'
2026-10-12T01:23:45Z    DeleteBucket    AssumedRole arn:aws:sts::123456789012:assumed-role/DevRole/hanako   203.0.113.10
2026-10-11T09:02:11Z    TerminateInstances  IAMUser arn:aws:iam::123456789012:user/taro 198.51.100.24
2026-10-10T05:40:00Z    AttachRolePolicy    IAMUser arn:aws:iam::123456789012:user/taro 198.51.100.24

日本時間で見たいときは、jq で変換します。この記事の jq のレシピ(日本時間への変換・IAM の変更の抽出・ユーザーでの絞り込み・アクセスキーでの検索)は、手元のサーバーの応答で動くことを確かめています。

jq -r '.Events[].CloudTrailEvent | fromjson
       | [(.eventTime | fromdateiso8601 + 9*3600 | strftime("%Y-%m-%d %H:%M:%S JST")), .eventName, .userIdentity.arn] | @tsv'

--query と --output table で表にした結果です(CLI の設定で cli_timestamp_format = iso8601 にした場合)。

--------------------------------------------------------------------------------------
|                                    LookupEvents                                    |
+---------------------------+----------------------+---------+-----------------------+
|  2026-10-12T10:23:45+09:00|  DeleteBucket        |  hanako |  my-old-bucket        |
|  2026-10-11T18:02:11+09:00|  TerminateInstances  |  taro   |  i-0123456789abcdef0  |
|  2026-10-10T14:40:00+09:00|  AttachRolePolicy    |  taro   |  app-role             |
+---------------------------+----------------------+---------+-----------------------+

AWS CLI v1 は、何も設定しないと EventTime を 1791768225.0 のような UNIX 時間の数値で表示しました。 ~/.aws/config に cli_timestamp_format = iso8601 を書くと、上のように ISO 8601 になります。AWS CLI v2 は既定で ISO 8601 です。jq で読むなら、CloudTrailEvent の中の eventTime(いつも ISO 8601 の文字列)を使うと、CLI の版に左右されません。

jq の書き方は、関連記事「jqの使い方|逆引き40例と実務レシピを全部実行結果つきで解説」で扱っています。

ページ送りと件数

AWS CLI は lookup-events のページ送りを自動で行い、全件を取ってきます。件数を区切るなら --max-items を使います。

aws cloudtrail lookup-events --max-items 2 \
  --query '[Events[].EventName, NextToken]' --output json
[
    [
        "DeleteBucket",
        "TerminateInstances"
    ],
    "eyJOZXh0VG9rZW4iOiBudWxsLCAiYm90b190cnVuY2F0ZV9hbW91bnQiOiAyfQ=="
]

続きは --starting-token に NextToken の値を渡して取ります。API は 1 秒に 2 回までなので、期間を広く取ると時間がかかります。--start-time と --end-time で期間を絞ってから検索すると速くなります。

90 日を超える調査:証跡(trail)+Athena

イベント履歴は 90 日で消えます。 それより前を調べるには、事前に証跡を作り、S3 にログを残しておく必要があります。証跡は、作った後のイベントしか保存しません。 調べたくなってから作っても、過去の分は戻りません。

証跡の作成

項目 料金(料金ページ)
イベント履歴の閲覧 無料
管理イベントの最初のコピーを S3 に送る 無料
管理イベントの追加のコピー 10 万件あたり $2.00
データイベント 10 万件あたり $0.10
S3 の保存・Athena の検索 それぞれのサービスの料金

S3 バケットのポリシー(ドキュメントの形)です。ACCOUNT_ID・REGION・TRAIL・BUCKET を自分の値にします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck20150319",
      "Effect": "Allow",
      "Principal": {"Service": "cloudtrail.amazonaws.com"},
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::BUCKET",
      "Condition": {"StringEquals": {"aws:SourceArn": "arn:aws:cloudtrail:REGION:ACCOUNT_ID:trail/TRAIL"}}
    },
    {
      "Sid": "AWSCloudTrailWrite20150319",
      "Effect": "Allow",
      "Principal": {"Service": "cloudtrail.amazonaws.com"},
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::BUCKET/AWSLogs/ACCOUNT_ID/*",
      "Condition": {"StringEquals": {"s3:x-amz-acl": "bucket-owner-full-control", "aws:SourceArn": "arn:aws:cloudtrail:REGION:ACCOUNT_ID:trail/TRAIL"}}
    }
  ]
}
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=ap-northeast-1
BUCKET=my-cloudtrail-logs-$ACCOUNT_ID
TRAIL=account-audit

aws s3api create-bucket --bucket "$BUCKET" \
  --create-bucket-configuration LocationConstraint=$REGION
aws s3api put-bucket-policy --bucket "$BUCKET" --policy file://bucket-policy.json

# 全リージョン・グローバルサービスのイベントを1つの証跡で
aws cloudtrail create-trail --name "$TRAIL" --s3-bucket-name "$BUCKET" \
  --is-multi-region-trail --include-global-service-events \
  --enable-log-file-validation
aws cloudtrail start-logging --name "$TRAIL"
aws cloudtrail get-trail-status --name "$TRAIL" --query IsLogging

moto で動かすと、create-trail は IsMultiRegionTrail・IncludeGlobalServiceEvents・LogFileValidationEnabled がすべて True の証跡を返し、get-trail-status の IsLogging は true でした。create-trail だけでは記録が始まらず、start-logging が要ります。

--enable-log-file-validation は、ログファイルが書き換えられていないかを、あとで確かめられるようにする設定です。S3 のバケットポリシーの書き方は、関連記事「S3バケットポリシーの書き方と例 IP制限・Condition早見表」で扱っています。

ログは、S3 の AWSLogs/アカウントID/CloudTrail/リージョン/年/月/日/ の下に保存されます。

Athena のテーブル(パーティション射影)

ドキュメントにある、パーティション射影(partition projection)を使うテーブル定義です。日付のパーティションを自動で扱うので、ALTER TABLE ADD PARTITION が要りません。 LOCATION と storage.location.template のバケット名・アカウント ID・リージョンを書き換えます。

CREATE EXTERNAL TABLE cloudtrail_logs_pp(
    eventversion STRING,
    useridentity STRUCT<
        type: STRING,
        principalid: STRING,
        arn: STRING,
        accountid: STRING,
        invokedby: STRING,
        accesskeyid: STRING,
        username: STRING,
        onbehalfof: STRUCT<
             userid: STRING,
             identitystorearn: STRING>,
        sessioncontext: STRUCT<
            attributes: STRUCT<
                mfaauthenticated: STRING,
                creationdate: STRING>,
            sessionissuer: STRUCT<
                type: STRING,
                principalid: STRING,
                arn: STRING,
                accountid: STRING,
                username: STRING>,
            ec2roledelivery:string,
            webidfederationdata: STRUCT<
                federatedprovider: STRING,
                attributes: map<string,string>>
        >
    >,
    eventtime STRING,
    eventsource STRING,
    eventname STRING,
    awsregion STRING,
    sourceipaddress STRING,
    useragent STRING,
    errorcode STRING,
    errormessage STRING,
    requestparameters STRING,
    responseelements STRING,
    additionaleventdata STRING,
    requestid STRING,
    eventid STRING,
    readonly STRING,
    resources ARRAY<STRUCT<
        arn: STRING,
        accountid: STRING,
        type: STRING>>,
    eventtype STRING,
    apiversion STRING,
    recipientaccountid STRING,
    serviceeventdetails STRING,
    sharedeventid STRING,
    vpcendpointid STRING,
    vpcendpointaccountid STRING,
    eventcategory STRING,
    addendum STRUCT<
      reason:STRING,
      updatedfields:STRING,
      originalrequestid:STRING,
      originaleventid:STRING>,
    sessioncredentialfromconsole STRING,
    edgedevicedetails STRING,
    tlsdetails STRUCT<
      tlsversion:STRING,
      ciphersuite:STRING,
      clientprovidedhostheader:STRING>
  )
PARTITIONED BY (
   `timestamp` string)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket/AWSLogs/account-id/CloudTrail/aws-region'
TBLPROPERTIES (
  'projection.enabled'='true',
  'projection.timestamp.format'='yyyy/MM/dd',
  'projection.timestamp.interval'='1',
  'projection.timestamp.interval.unit'='DAYS',
  'projection.timestamp.range'='2020/01/01,NOW',
  'projection.timestamp.type'='date',
  'storage.location.template'='s3://amzn-s3-demo-bucket/AWSLogs/account-id/CloudTrail/aws-region/${timestamp}')
書き換える所 内容
amzn-s3-demo-bucket 証跡のバケット名
account-id アカウント ID
aws-region リージョン(例 ap-northeast-1)
projection.timestamp.range の開始日 ログを残し始めた日。ドキュメントの例は 2020/01/01

このテーブルは1つのリージョン分です。 IAM などのグローバルサービスのイベントは us-east-1 の下に入るので、aws-region を us-east-1 にしたテーブル(例 cloudtrail_logs_use1)も作っておきます。

検索では、WHERE に必ず timestamp(日付のパーティション)を入れます。 入れないと全期間を読み、検索の料金と時間が増えます。

Athena のクエリ例

誰が消したか(期間を指定)

SELECT eventtime,
       eventname,
       useridentity.type AS who_type,
       useridentity.arn AS who,
       sourceipaddress,
       json_extract_scalar(requestparameters, '$.bucketName') AS bucket
FROM cloudtrail_logs_pp
WHERE timestamp BETWEEN '2026/01/01' AND '2026/06/30'
  AND eventname IN ('DeleteBucket', 'TerminateInstances', 'DeleteDBInstance', 'DeleteTable', 'DeleteVolume')
ORDER BY eventtime DESC;

ドキュメントには、resources の配列を UNNEST して、消されたバケットの名前を取り出す例があります。

SELECT
    awsregion,
    replace(unnested.resources_entry.ARN,'arn:aws:s3:::') as deleted_bucket,
    eventtime AS time_deleted,
    useridentity.username,
    unnested.resources_entry.accountid as bucket_acct_id
FROM cloudtrail_logs t
CROSS JOIN UNNEST(t.resources) unnested (resources_entry)
WHERE eventname = 'DeleteBucket'
ORDER BY eventtime

(ドキュメントの例はテーブル名が cloudtrail_logs です。上のテーブル定義を使うなら cloudtrail_logs_pp にし、timestamp の条件を足します。)

誰が IAM の権限を変えたか(us-east-1 のテーブル)

SELECT eventtime,
       eventname,
       useridentity.arn AS who,
       sourceipaddress,
       coalesce(json_extract_scalar(requestparameters, '$.roleName'),
                json_extract_scalar(requestparameters, '$.userName'),
                json_extract_scalar(requestparameters, '$.groupName')) AS target,
       json_extract_scalar(requestparameters, '$.policyArn') AS policy_arn
FROM cloudtrail_logs_use1
WHERE timestamp >= '2026/04/01'
  AND eventsource = 'iam.amazonaws.com'
  AND readonly = 'false'
  AND errorcode IS NULL
ORDER BY eventtime DESC
LIMIT 200;

コンソールへのログイン履歴(失敗も含む)

SELECT eventtime,
       useridentity.type,
       coalesce(useridentity.username, useridentity.arn) AS who,
       sourceipaddress,
       json_extract_scalar(responseelements, '$.ConsoleLogin') AS result,
       json_extract_scalar(additionaleventdata, '$.MFAUsed') AS mfa,
       errormessage
FROM cloudtrail_logs_use1
WHERE timestamp >= '2026/07/01'
  AND eventname = 'ConsoleLogin'
ORDER BY eventtime DESC;

特定の人(ロールのセッション名)の変更操作

SELECT eventtime, awsregion, eventsource, eventname, sourceipaddress, errorcode
FROM cloudtrail_logs_pp
WHERE timestamp BETWEEN '2026/09/01' AND '2026/09/30'
  AND useridentity.arn LIKE '%/hanako'
  AND readonly = 'false'
ORDER BY eventtime;

権限がなくて失敗した操作

SELECT useridentity.arn AS who, eventsource, eventname, errorcode, count(*) AS n
FROM cloudtrail_logs_pp
WHERE timestamp >= '2026/10/01'
  AND errorcode IN ('AccessDenied', 'AccessDeniedException', 'Client.UnauthorizedOperation')
GROUP BY 1, 2, 3, 4
ORDER BY n DESC
LIMIT 50;

CLI からクエリを実行する

QID=$(aws athena start-query-execution \
  --work-group primary \
  --query-execution-context Database=default \
  --result-configuration OutputLocation=s3://my-athena-results/ \
  --query-string "SELECT eventtime, eventname, useridentity.arn FROM cloudtrail_logs_pp WHERE timestamp >= '2026/10/01' AND eventname = 'DeleteBucket'" \
  --query QueryExecutionId --output text)

aws athena get-query-execution --query-execution-id "$QID" \
  --query 'QueryExecution.Status.State' --output text   # SUCCEEDED になるまで待つ

aws athena get-query-results --query-execution-id "$QID" \
  --query 'ResultSet.Rows[].Data[].VarCharValue' --output text

requestparameters などは JSON の文字列として入っているので、json_extract_scalar(列, '$.キー') で値を取り出します。useridentity は構造体なので、useridentity.arn のように . でたどれます。

CloudTrail Lake の位置づけ

CloudTrail Lake は、イベントを専用の保存先(イベントデータストア)に集め、SQL で検索できる CloudTrail の機能です。 Athena と違って S3 のバケットやテーブル定義を用意せず、複数のリージョン・アカウントをまとめて検索できます。

項目 イベント履歴 証跡+Athena CloudTrail Lake
期間 90 日 S3 に残す限り 最大 3,653 日(約10年)または 2,557 日(約7年)。料金の選択肢による
検索 条件1つ+時刻 SQL SQL(Trino の SELECT)
複数リージョン 1 回に1つ テーブルの作り方次第 まとめて
準備 なし 証跡・バケット・テーブル イベントデータストア
料金 無料 S3 の保存・Athena のスキャン量 取り込み・保存・スキャン量
新規の利用 — — 2026年5月31日から、新しい利用者は使い始められない(既存の利用者はそのまま使える)

ドキュメントでは、CloudTrail Lake は 2026年5月31日以降、新しい利用者を受け付けないとされています。これから長期の調査の仕組みを作るなら、証跡+Athena が使える方法です。

よくある質問

Q. lookup-events で何も出ません。 A. リージョンを確かめます。IAM・STS・CloudFront の操作は主に us-east-1、コンソールのログインは表のリージョンに記録されます。90 日より前の操作や、S3 の GetObject・PutObject・DeleteObject のようなデータイベントは出ません。

Q. 操作した IP アドレスが ec2.amazonaws.com のようなサービス名になっています。 A. AWS のサービスが利用者の代わりに API を呼んだときは、sourceIPAddress にサービス名が入ることがあります。userIdentity.invokedBy も合わせて見ます。

Q. 失敗した操作も記録されますか。 A. 記録されます。errorCode・errorMessage に理由が入ります。AccessDenied が続いている利用者は、権限を探っている可能性もあるので確かめます。

Q. コンソールでの操作と CLI での操作は見分けられますか。 A. userAgent を見ます。CLI なら aws-cli/...、SDK なら Boto3/... などが入ります。

Q. 証跡のログは改ざんされていないと言えますか。 A. --enable-log-file-validation を有効にしておくと、aws cloudtrail validate-logs でログファイルが書き換えられていないかを確かめられます。

まとめ

  • 直近 90 日の管理イベントは aws cloudtrail lookup-events(無料)。条件は1つ・1 リージョン・1 秒 2 回
  • IAM の変更は us-east-1 で検索する。ログインはルートか IAM ユーザーかで記録先が変わる
  • 詳細は CloudTrailEvent(文字列)を jq の fromjson で読む。誰かは userIdentity、どこからは sourceIPAddress
  • AssumedRole は ARN の最後のセッション名・sessionIssuer・sourceIdentity で人をたどる
  • 90 日を超える・データイベントを見るなら、事前に証跡(create-trail + start-logging)を作り、Athena で timestamp を絞って SQL
  • CloudTrail Lake は 2026年5月31日から新規の利用者は使い始められない

参考・出典

確認日はいずれも 2026年10月12日です。

  • AWS CloudTrail API リファレンス「LookupEvents」:https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_LookupEvents.html
  • AWS CLI コマンドリファレンス「lookup-events」:https://docs.aws.amazon.com/cli/latest/reference/cloudtrail/lookup-events.html
  • AWS CloudTrail ユーザーガイド「Working with CloudTrail event history」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events.html
  • AWS CloudTrail ユーザーガイド「CloudTrail concepts(Global service events)」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-concepts.html
  • AWS CloudTrail ユーザーガイド「CloudTrail userIdentity element」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html
  • AWS CloudTrail ユーザーガイド「AWS Management Console sign-in events」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-aws-console-sign-in-events.html
  • AWS CloudTrail ユーザーガイド「Amazon S3 bucket policy for CloudTrail」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-s3-bucket-policy-for-cloudtrail.html
  • AWS CloudTrail ユーザーガイド「Working with AWS CloudTrail Lake」:https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-lake.html
  • AWS CloudTrail の料金:https://aws.amazon.com/cloudtrail/pricing/
  • Amazon Athena ユーザーガイド「Create the table for CloudTrail logs in Athena using partition projection」:https://docs.aws.amazon.com/athena/latest/ug/create-cloudtrail-table-partition-projection.html
  • Amazon Athena ユーザーガイド「Example CloudTrail log queries」:https://docs.aws.amazon.com/athena/latest/ug/query-examples-cloudtrail-logs.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「CloudTrailで誰が操作したか調べる|lookup-eventsとAthena」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?