CloudTrail Lakeの代わりにCloudWatch Logs Insightsがなれるか検証してみた
こんにちは、せーのです。
今日はCloudTrail Lakeの新規受け入れ停止アナウンスを受けて、Amazon CloudWatch Logs Insightsでどこまで代替できるのかを整理してみました。
CloudTrail Lakeは「終了」ではなく「新規受け入れ停止」ですが、これから新しいアカウントや運用をどう設計するかは考え直しが必要になりますよね。
ということで今回は、公式情報をおさらいしつつ、実際に同一条件でCloudTrail LakeとCloudWatch Logs Insightsに同じ問いを投げ、代替性を実測で確認しました。
CloudTrail Lake 新規受け入れ停止とは(おさらい)
まず前提です。公式ドキュメントの要点は次の通りです。
- 2026-05-31でCloudTrail Lakeの新規顧客受け入れ停止
- 既存顧客は継続利用可能(いきなり使えなくなるわけではない)
- サービスはメンテナンスモード寄りになり、新機能追加より保守中心
- AWSとしては、移行先としてAmazon CloudWatchの利用を案内
つまり「今動いているものは急停止しないが、新しく作るなら別の選択肢を見ておいた方がよい」という温度感です。
何が気になったのか
管理イベントを見るだけならCloudWatchでもそこまで困らない印象ですが、モヤッとするのはデータイベントです。
特に、以下のような監査をLake SQLで組んでいる場合は気になります。
- IAMユーザー単位でS3アクセスを追う
- バケットとプレフィックス単位でアクセス範囲を絞る
- 稀アクセス(countが小さいもの)をあぶり出す
- 書き込みのみ(readOnly=false)を抽出する
ここがCloudWatch Logs Insightsで同等に書けるのか、そして運用で困らないのか、というのが今回の主題です。
今回の検証方針
今回の検証では、入口をそろえて比較する方針にしています。
- CloudTrail Trail(S3 + CloudWatch Logs配信)
- CloudTrail Lake EDS
この2つに同一のAdvanced Event Selectorsを設定し、同じデータイベントを入れます。
以降の表記は、次の2つで統一します。
- Lake側: CloudTrail Lake SQLで検索する経路
- CWL側: CloudWatch Logs Insightsで検索する経路
同じ入力に対して出力結果(件数・抽出対象)が一致するかを見れば、代替性を実測で判断しやすくなります。
やってみた
検証環境
- リージョン:
ap-northeast-1 - データイベント対象: S3バケット2つ(以下、
Bucket A/Bucket B) - 各バケット内の検証プレフィックス:
critical/backup/rare/ - 比較対象: CloudTrail Lake(Lake SQL)/ CloudWatch Logs Insights
Trail と Lake EDS に同一の Advanced Event Selectorsを設定して並走させ、同じ S3 データイベントを両方に流しました。
先に比較結果を示すと、次のとおりです(詳細手順はこのあとで説明します)。
| クエリ | Lake 件数 | CWL 件数 | 一致 |
|---|---|---|---|
| Q1: 特定ユーザーの全S3データイベント | 10 | 10 | ✅ |
| Q2: 特定バケット / rare のアクセス | 1 | 1 | ✅ |
| Q3: 稀アクセス(count < 5)検出 | 7 | 7 | ✅ |
| Q4: 書き込みのみ(readOnly=false) | 10 | 10 | ✅ |
Terraform で環境を一気に立ち上げる
まず Terraform で検証環境を構築します。Trail・Lake EDS・S3バケット2つ・IAMユーザー・CloudWatch Logs Group など24リソースが一括で作成されます。
terraform apply -auto-approve
# Apply complete! Resources: 24 added, 0 changed, 0 destroyed.
1〜2分で完成。Trail のログ配信先と Lake EDS に同一のセレクターが設定されていることを確認してから、次に進みます。
注意点: Trail apply 直後(今回は約30秒後)にシミュレートを実行したところ、Management イベントは記録されたものの S3 Data イベントが一切キャプチャされませんでした。Trail の Advanced Event Selector が完全に有効になるまでに数分かかるようです。Trail 作成後は 3〜5 分待ってからシミュレートを開始することを推奨します。
ダミーアドミンに動いてもらう
Terraform が生成した IAM ユーザー lake-vs-cwl-dummy-admin のアクセスキーを使って、S3 操作を流します。
# 認証情報を取得
AWS_ACCESS_KEY_ID=$(terraform output -raw dummy_admin_access_key_id)
AWS_SECRET_ACCESS_KEY=$(terraform output -raw dummy_admin_secret_access_key)
# critical/ に5回 PUT(頻繁アクセス)
for i in 1 2 3 4 5; do
echo "test-$i" | aws s3 cp - "s3://${BUCKET_A}/critical/file-${i}.txt"
done
# rare/ に1回 PUT(稀アクセス)
echo "once" | aws s3 cp - "s3://${BUCKET_A}/rare/once-a.txt"
上のコードは Bucket A 側の例です。Bucket B 側も同様のプレフィックス・件数で実行しています。
Bucket A と Bucket B の両方に同一条件で PutObject を流し、2バケット合計で10件(各バケット5件)を実行しました。
対象プレフィックスは critical/ backup/ rare/ です。
配信を待つ
実測した配信遅延は以下のとおりです。
| 配信先 | 遅延(操作完了から) |
|---|---|
| Trail → S3 バケット(ログファイル) | 約 5 分 |
| Trail → CloudWatch Logs | 約 10 分 |
| Trail → CloudTrail Lake EDS | 約 10 分 |
aws cloudtrail get-trail-status で LatestCloudWatchLogsDeliveryTime がシミュレート時刻より新しくなっていれば配信済みのサインです。
また、CloudTrail の S3 ログは Data イベントと Management イベントが別ファイルに分けて配信されるという挙動も確認できました。管理イベントのバッチが先に来て、数分後に Data イベントのバッチが別ファイルで届きます。
2サイドで同じ問いを投げる
両サービスで同一のクエリを並行実行しました。
# Lake SQL(Q1: dummy-admin の全 Data イベント)
QID=$(aws cloudtrail start-query \
--query-statement "SELECT eventTime, eventName, userIdentity.arn,
element_at(resources, 1).ARN AS resourceArn,
element_at(requestParameters, 'key') AS objectKey
FROM ${EDS_ID}
WHERE eventCategory = 'Data'
AND userIdentity.arn LIKE '%lake-vs-cwl-dummy-admin'
ORDER BY eventTime DESC" \
--query 'QueryId' --output text)
# CWL Insights(Q1: 同等クエリ)
aws logs start-query \
--log-group-name /aws/cloudtrail/lake-vs-cwl-trail \
--query-string 'fields @timestamp, eventName, userIdentity.arn, resources.0.ARN
| filter eventCategory = "Data"
| filter userIdentity.arn like /lake-vs-cwl-dummy-admin/
| sort @timestamp desc | limit 100'
答え合わせ
| クエリ | Lake 件数 | CWL 件数 | 一致 |
|---|---|---|---|
| Q1: 特定ユーザーの全S3データイベント | 10 | 10 | ✅ |
| Q2: 特定バケット / rare のアクセス | 1 | 1 | ✅ |
| Q3: 稀アクセス(count < 5)検出 | 7 | 7 | ✅ |
| Q4: 書き込みのみ(readOnly=false) | 10 | 10 | ✅ |
全クエリで Lake と CWL Insights の件数が完全一致しました。
Q3 の稀アクセス検出では、rare/once-a.txt(1回)から critical/file-1.txt(Bucket A と B の両方に PUT したので count=2)まで、両者まったく同じ内訳で返ってきました。
注意点:readOnly の boolean 表現
Q4 で一つ引っかかった点がありました。Lake SQL では readOnly = false が動きますが、CWL Insights で filter readOnly = false だけを書くと期待した件数が取れないことがあります。
# CWL Insights の実際の出力
readOnly: 0 ← false ではなく 0 で返る場合がある
今回は filter readOnly = 0 or readOnly = false の OR で書いて解決しました。どちらで返るかはイベント種別によって異なるため、両方を OR で書いておくのが安全です。
Lake SQL → CloudWatch Logs Insights 書き換え早見表
実際に書き換える際の変換表をつくりました。参考にしてください。
| やりたいこと | Lake SQL | CloudWatch Logs Insights |
|---|---|---|
| 配列の先頭要素参照 | element_at(resources, 1).ARN |
resources.0.ARN |
| Mapからキー取得 | element_at(requestParameters, 'key') |
requestParameters.key |
| IAM ユーザー名で絞る | WHERE userIdentity.userName = 'admin-user' |
filter userIdentity.userName = "admin-user" |
| 特定ユーザーで絞る | WHERE userIdentity.arn LIKE '%dummy-admin' |
filter userIdentity.arn like /dummy-admin/ |
| プレフィックスで絞る | LIKE 'rare/%' |
like /^rare\// |
| 集計後フィルタ | GROUP BY ... HAVING count(*) < N |
stats count() as c by ... | filter c < N |
| 書き込み判定 | readOnly = false |
readOnly = 0 or readOnly = false |
Lake SQL側の注意としては、requestParameters['key']のような書き方だと、キーがない行で失敗しやすい点です。
element_at(requestParameters, 'key')を使うとNULLで処理できるので安全でした。
運用で気をつけるポイント
代替可能かどうかとは別に、運用上の差分は押さえておきたいです。
1. CloudWatch Logsのサイズ上限
CloudWatch Logsは1イベントあたり256KB上限があります。通常のS3操作ログでは大きな問題になりづらいですが、サイズが膨らむイベントは注意が必要です。
2. Logs Insightsのクエリ時間制限
Logs Insightsはクエリ実行時間に上限があるため、長期間を1発で調べる運用には向きません。
長期監査はS3 + Athenaを併用し、CloudWatchは直近調査のホットストアとして使い分けるのが現実的です。
3. 履歴データ移行の扱い
移行設計では「いつからのデータを移せるか」を必ず確認しておく必要があります。
期間要件が厳しい監査では、先にエクスポート方針まで決めておくと後で困りにくいです。
4. Trail作成直後のデータイベント取りこぼし
今回の実測で再現性に影響しやすかったのはここです。terraform apply の直後にシミュレートを始めると、Managementイベントは来るのにDataイベントが来ないケースがありました。
おそらくAdvanced Event Selectorsの有効化待ちだと推測できます。Trail作成後は、3〜5分待ってからデータイベントを流す運用にすると安全です。
コスト感(ざっくり)
今回の比較で使う範囲だと、取り込み単価もクエリ単価も両者は大きく乖離しません。
なので実際の判断軸は「料金差」より「運用設計(検索DSL、保持、運用負荷)」になりやすいと感じています。
まとめ
CloudTrail Lakeの新規受け入れ停止を受けて、CloudWatch Logs Insightsへの移行は十分に現実的な選択肢になりそうです。
ただし、SQLがそのまま移植できるわけではなく、クエリの書き換えと運用設計の見直しは必要です。
実際に検証してみた結果、Q1〜Q4 のすべてで Lake と CWL Insights の件数が完全一致しました。
データイベント監査においても、CloudWatch Logs Insights は CloudTrail Lake SQL の実質的な代替として機能することが確認できました。
ただし一点だけ注意が必要で、readOnly の扱いが Lake(false)と CWL(0)で異なる場合があります。クエリ移行時は readOnly = 0 or readOnly = false の OR で書いておくと安全です。
加えて、Trail作成直後の取りこぼしを避けるために「環境作成後に少し待ってからシミュレートする」手順を運用に入れておくと、検証再現性が安定します。





