S3サーバーアクセスログの新機能、CloudWatch Logs配信とS3 Tables連携を試してみた
はじめに
2026年6月29日、S3サーバーアクセスログの新しい配信先としてAmazon CloudWatch Logsが追加されました。
従来はテキスト形式でS3バケットへ配信されるだけだったアクセスログが、CloudWatch Logsへ構造化JSONとして配信されるようになりました。ログ到着後はCloudWatch Logs Insightsでそのままクエリできるほか、S3 Tables連携を設定することでApache Iceberg形式の管理済みテーブルとしてAthenaからSQL分析できます。
従来の配信方式(S3バケット宛テキスト形式)と新方式の主な違いは以下のとおりです。
| CloudWatch Logs 配信(新) | S3バケット配信(従来) | |
|---|---|---|
| フォーマット | 構造化JSON | スペース区切りテキスト |
| クエリ手段 | CloudWatch Logs Insights / Athena (S3 Tables) | Athena(要テーブル定義) |
| パース処理 | JSONフィールドとして利用可能 | スペース区切りテキストのパースが必要 |
| クロスアカウント集約 | 対応 | 非対応(同一アカウントのみ) |
| クロスリージョン集約 | 対応 | 非対応(同一リージョンのみ) |
| KMS暗号化 | 対応 | 制約あり(条件付きでSSE-KMS可) |
| SQL分析 | S3 Tables連携により管理済みテーブルとして利用可能 | Athenaテーブル定義やパース設定が必要 |
| 追加コスト | CloudWatch Logs 取り込み・保存料金 | ストレージ料金のみ |
今回は、新規バケットに対してCloudWatch Logs配信と従来のS3バケット配信を並行設定しました。テストリクエストを発行した後、CloudWatch Logs InsightsとAthena(S3 Tables)でクエリするところまでを確認します。
検証環境
- リージョン: ap-northeast-1(東京)
- AWS CLI: v2.35.12
リソース作成
S3バケット
aws s3api create-bucket \
--bucket sal-cw-s3tables-demo-20260630 \
--region ap-northeast-1 \
--create-bucket-configuration LocationConstraint=ap-northeast-1
aws s3api create-bucket \
--bucket sal-cw-s3tables-demo-20260630-logs \
--region ap-northeast-1 \
--create-bucket-configuration LocationConstraint=ap-northeast-1
CloudWatch Logs ロググループ
プレフィックスは /aws/vendedlogs/ 配下にする必要があります。ログクラスはStandardを指定しました。Infrequent AccessクラスではLogs Insightsのクエリ機能に一部制約があるためです。
aws logs create-log-group \
--log-group-name /aws/vendedlogs/s3/sal-cw-s3tables-demo \
--region ap-northeast-1
aws logs put-retention-policy \
--log-group-name /aws/vendedlogs/s3/sal-cw-s3tables-demo \
--retention-in-days 30 \
--region ap-northeast-1
IAMロール(S3 Tables連携用)
S3 Tablesへのログ配信には、CloudWatch LogsがAssumeRoleするためのIAMロールが必要です。
信頼ポリシーでは logs.amazonaws.com をプリンシパルとし、Conditionで対象アカウントとロググループを制限します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logs.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/vendedlogs/s3/sal-cw-s3tables-demo"
}
}
}
]
}
権限ポリシーは logs:integrateWithS3Table アクションのみを許可します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:integrateWithS3Table",
"Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/vendedlogs/s3/sal-cw-s3tables-demo",
"Condition": {
"StringEquals": {
"aws:ResourceAccount": "123456789012"
}
}
}
]
}
aws iam create-role \
--role-name CWLogsS3TableIntegrationRole-demo \
--assume-role-policy-document file://trust-policy.json
aws iam put-role-policy \
--role-name CWLogsS3TableIntegrationRole-demo \
--policy-name CWLogsS3TableIntegrationPolicy \
--policy-document file://permission-policy.json
従来のアクセスログ配信設定
従来のアクセスログ配信設定(比較用)
ログ配信先バケットに、S3ログ配信サービスからの書き込みを許可するバケットポリシーを設定します。
aws s3api put-bucket-policy \
--bucket sal-cw-s3tables-demo-20260630-logs \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "logging.s3.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::sal-cw-s3tables-demo-20260630-logs/access-logs/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
}
}
}
]
}' \
--region ap-northeast-1
ソースバケットのログ配信を有効化します。
aws s3api put-bucket-logging \
--bucket sal-cw-s3tables-demo-20260630 \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "sal-cw-s3tables-demo-20260630-logs",
"TargetPrefix": "access-logs/"
}
}' \
--region ap-northeast-1
CloudWatch Logs配信設定
Delivery Source の作成
aws logs put-delivery-source \
--name sal-demo-source \
--resource-arn arn:aws:s3:::sal-cw-s3tables-demo-20260630 \
--log-type S3_SERVER_ACCESS_LOGS \
--region ap-northeast-1
{
"deliverySource": {
"name": "sal-demo-source",
"arn": "arn:aws:logs:ap-northeast-1:123456789012:delivery-source:sal-demo-source",
"resourceArns": [
"arn:aws:s3:::sal-cw-s3tables-demo-20260630"
],
"service": "s3",
"logType": "S3_SERVER_ACCESS_LOGS"
}
}
Delivery Destination の作成
aws logs put-delivery-destination \
--name sal-demo-destination \
--delivery-destination-configuration '{
"destinationResourceArn": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/vendedlogs/s3/sal-cw-s3tables-demo"
}' \
--region ap-northeast-1
{
"deliveryDestination": {
"name": "sal-demo-destination",
"arn": "arn:aws:logs:ap-northeast-1:123456789012:delivery-destination:sal-demo-destination",
"deliveryDestinationType": "CWL",
"deliveryDestinationConfiguration": {
"destinationResourceArn": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/vendedlogs/s3/sal-cw-s3tables-demo"
}
}
}
Delivery の作成
ソースとデスティネーションをリンクすると、配信が開始されます。
aws logs create-delivery \
--delivery-source-name sal-demo-source \
--delivery-destination-arn arn:aws:logs:ap-northeast-1:123456789012:delivery-destination:sal-demo-destination \
--region ap-northeast-1
レスポンスの recordFields には、配信対象となりうるフィールド一覧が含まれます。今回は29フィールドが定義されていました(リクエスト内容によって一部フィールドが未出力になる場合があります)。
{
"delivery": {
"id": "ishXsUfkyCuKMVtD",
"arn": "arn:aws:logs:ap-northeast-1:123456789012:delivery:ishXsUfkyCuKMVtD",
"deliverySourceName": "sal-demo-source",
"deliveryDestinationArn": "arn:aws:logs:ap-northeast-1:123456789012:delivery-destination:sal-demo-destination",
"deliveryDestinationType": "CWL",
"recordFields": [
"schema_version_id",
"bucket_arn",
"bucket_name",
"request_time",
"bucket_owner_id",
"remote_ip",
"requester",
"request_id",
"operation",
"key_name",
"request_uri",
"http_status",
"error_code",
"bytes_sent_size",
"object_size",
"total_duration",
"turn_around_duration",
"referer",
"user_agent",
"version_id",
"host_id",
"signature_version",
"cipher_suite",
"authentication_type",
"host_header",
"tls_version",
"access_point_arn",
"acl_required",
"source_region"
]
}
}
S3 Tables連携の有効化
S3 Tables連携はアカウント・リージョン単位で作成し、S3アクセスログのデータソースを関連付けることで、対象のCloudWatch Logs配信ログがApache Iceberg形式の管理済みテーブルとしてS3 Tablesに格納されます。
aws observabilityadmin create-s3-table-integration \
--role-arn arn:aws:iam::123456789012:role/CWLogsS3TableIntegrationRole-demo \
--encryption '{"SseAlgorithm":"AES256"}' \
--region ap-northeast-1
{
"Arn": "arn:aws:observabilityadmin:ap-northeast-1:123456789012:s3tableintegration/evku8gpxr3pn42eqdfedhrvbr"
}
次に、S3アクセスログのデータソースを関連付けます。
aws logs associate-source-to-s3-table-integration \
--integration-arn arn:aws:observabilityadmin:ap-northeast-1:123456789012:s3tableintegration/evku8gpxr3pn42eqdfedhrvbr \
--data-source '{"name":"amazon_s3","type":"server_access"}' \
--region ap-northeast-1
{
"identifier": "24313a0f-2924-4b5f-a42c-eb8929a4f76a"
}
テストリクエストの発行
ログを生成するために、ソースバケットに対して以下の7つのコマンドを実行しました。
# PUT(3ファイル)
echo "test content 1" | aws s3 cp - s3://sal-cw-s3tables-demo-20260630/test/file1.txt
echo "test content 2" | aws s3 cp - s3://sal-cw-s3tables-demo-20260630/test/file2.txt
echo "test content 3" | aws s3 cp - s3://sal-cw-s3tables-demo-20260630/test/file3.txt
# GET
aws s3 cp s3://sal-cw-s3tables-demo-20260630/test/file1.txt /tmp/downloaded.txt
# LIST
aws s3 ls s3://sal-cw-s3tables-demo-20260630/test/
# HEAD
aws s3api head-object --bucket sal-cw-s3tables-demo-20260630 --key test/file2.txt
# DELETE
aws s3 rm s3://sal-cw-s3tables-demo-20260630/test/file3.txt
ログの確認
テストリクエスト発行から約50分後にCloudWatch Logsへログが到着しました。公式ドキュメントでは配信まで数時間かかる場合があるとされており、best-effort配信のためタイミングは保証されません。
CloudWatch Logsのログ形式
CloudWatch Logsに配信されたログは、1レコード1行の構造化JSONです。以下は到着した1レコードの例です。
{
"schema_version_id": "V_1_0",
"bucket_arn": "arn:aws:s3:::sal-cw-s3tables-demo-20260630",
"bucket_name": "sal-cw-s3tables-demo-20260630",
"request_time": "2026-06-30T01:31:22.000Z",
"bucket_owner_id": "cd31ac5589...",
"remote_ip": "133.201.xx.xx",
"requester": "arn:aws:sts::123456789012:assumed-role/cm-user.name/cm-user.name",
"request_id": "MWT6320RGF2TTJ98",
"operation": "REST.PUT.LOGGING_STATUS",
"request_uri": "PUT /?logging HTTP/1.1",
"http_status": 200,
"total_duration": 328,
"user_agent": "aws-cli/2.35.12 ...",
"signature_version": "SigV4",
"cipher_suite": "TLS_AES_128_GCM_SHA256",
"authentication_type": "AuthHeader",
"host_header": "sal-cw-s3tables-demo-20260630.s3.ap-northeast-1.amazonaws.com",
"tls_version": "TLSv1.3",
"acl_required": false
}
requester フィールドにはAssumed RoleのARNがセッション名付きで記録されており、従来のS3バケット配信ではロール名までしか確認できなかったケースと比べて、アクセス元を追跡するための手がかりが増えています。
CloudWatch Logs Insights でのクエリ
各レコードがフラットな構造化JSONのため、フィールド名をそのまま指定してクエリできます。
オペレーション別リクエスト数
stats count(*) as request_count by operation
| sort request_count desc
| operation | request_count |
|---|---|
| REST.OPTIONS.PREFLIGHT | 43 |
| REST.GET.LOGGING_STATUS | 11 |
| REST.GET.NOTIFICATION | 8 |
| REST.GET.ACCELERATE | 8 |
| REST.GET.BUCKET_TAGS | 7 |
| REST.HEAD.BUCKET | 7 |
| REST.PUT.OBJECT | 4 |
| REST.HEAD.OBJECT | 4 |
| REST.GET.OBJECT | 3 |
| REST.DELETE.OBJECT | 1 |
テストリクエスト7件に対し、AWS ConfigやAccess Analyzerなどのサービスによる確認リクエストやコンソール操作も含め、合計163レコードを確認しました(各表は集計時点・フィルタ条件が異なるため件数は完全には一致しません)。
エラーステータス分析
filter http_status >= 400
| stats count(*) as error_count by http_status, error_code, operation
| sort error_count desc
| http_status | error_code | operation | error_count |
|---|---|---|---|
| 404 | ReplicationConfigurationNotFoundError | REST.GET.REPLICATION | 6 |
| 404 | NoSuchLifecycleConfiguration | REST.GET.LIFECYCLE | 4 |
| 404 | NoSuchWebsiteConfiguration | REST.GET.WEBSITE | 3 |
| 404 | NoSuchBucketPolicy | REST.GET.BUCKETPOLICY | 3 |
| 404 | ObjectLockConfigurationNotFoundError | REST.GET.OBJECT_LOCK_CONFIGURATION | 3 |
今回確認された404は、Replication、Lifecycle、Websiteなど未設定の項目を確認した際の応答であり、この検証環境では想定内の結果です。エラーコードごとに集計できるため、実際の問題の切り分けが容易になります。
リクエスター別アクセス集計
stats count(*) as request_count by requester
| sort request_count desc
| requester | request_count |
|---|---|
| arn:aws:sts::123456789012:assumed-role/cm-user.name/cm-user.name | 96 |
| (記録なし) | 44 |
| arn:aws:sts::123456789012:assumed-role/AWSServiceRoleForConfig/AWSConfig-Describe | 17 |
| arn:aws:sts::123456789012:assumed-role/AWSServiceRoleForAccessAnalyzer/access-analyzer | 4 |
Assumed Roleのセッション名まで記録されるため、IAMロールを共有している環境でもセッション名を手がかりにユーザーやサービスを追跡しやすくなります。
Athena (S3 Tables) でのクエリ
Athenaからはカタログ s3tablescatalog/aws-cloudwatch 経由でアクセスします。階層構造は以下のとおりです。
- カタログ:
s3tablescatalog/aws-cloudwatch - データベース:
logs - テーブル:
amazon_s3__server_access
SHOW TABLES IN logs
-- 結果: amazon_s3__server_access
オペレーション別リクエストミックス
SELECT operation, COUNT(*) as request_count
FROM amazon_s3__server_access
WHERE bucket_name = 'sal-cw-s3tables-demo-20260630'
GROUP BY operation
ORDER BY request_count DESC
LIMIT 10
CloudWatch Logs Insightsと同様の傾向が得られました。テーブル定義やパーティション設定を自分で管理する必要はありません。以下では、AthenaからSQLで分析する例を示します。
レイテンシ分析(p50/p95)
SELECT operation,
COUNT(*) as cnt,
approx_percentile(total_duration, 0.5) as p50_ms,
approx_percentile(total_duration, 0.95) as p95_ms
FROM amazon_s3__server_access
WHERE bucket_name = 'sal-cw-s3tables-demo-20260630'
AND total_duration IS NOT NULL
GROUP BY operation
HAVING COUNT(*) >= 3
ORDER BY p95_ms DESC
| operation | cnt | p50_ms | p95_ms |
|---|---|---|---|
| REST.GET.BUCKET_TAGS | 7 | 25 | 67 |
| REST.GET.LOGGING_STATUS | 12 | 22 | 48 |
| REST.PUT.OBJECT | 4 | 41 | 42 |
| REST.HEAD.OBJECT | 4 | 29 | 35 |
| REST.GET.OBJECT | 3 | 26 | 31 |
| REST.OPTIONS.PREFLIGHT | 43 | 3 | 5 |
approx_percentile() で複数パーセンタイルを一度に算出でき、他テーブルとの結合も容易です。
ソースIP別アクセスパターン
SELECT remote_ip,
COUNT(*) as request_count,
COUNT(DISTINCT operation) as distinct_ops
FROM amazon_s3__server_access
WHERE bucket_name = 'sal-cw-s3tables-demo-20260630'
GROUP BY remote_ip
ORDER BY request_count DESC
| remote_ip | request_count | distinct_ops |
|---|---|---|
| 133.201.xx.xx | 141 | 29 |
| (null) | 24 | 19 |
まとめ
S3サーバーアクセスログの新機能としてCloudWatch Logs配信が追加されたことで、従来よりもログ分析に取り組みやすくなりました。従来のS3バケット配信ではスペース区切りテキストが出力されるため、Athenaで分析するにはテーブル定義やパース設定の管理が必要でした。一方、CloudWatch Logs配信ではログが構造化JSONとして配信されるため、ログ到着後はCloudWatch Logs Insightsでフィールドを指定してクエリできます。さらにS3 Tables連携を設定することで、AthenaからApache Iceberg形式のテーブルとしてSQL分析できることも確認できました。
CloudTrailデータイベントとの使い分けは、目的に応じて考えるのがよさそうです。S3サーバーアクセスログには total_duration、object_size、bytes_sent_size など、アクセスパターンやレイテンシ分析に役立つフィールドがあります。一方、CloudTrailデータイベントはAPI操作の追跡や監査証跡としての利用に向いています。コスト面では、参照を含むすべてのデータイベントをCloudTrailで記録した場合、リクエスト数に応じた課金が高額になることがあります。配信の遅延が許容できるワークロードや、Athenaでのクエリ処理を多用する用途であれば、S3サーバーアクセスログ+S3 Tables連携の方がコスト効率に優れる場合があります。
S3のアクセスログ記録には、CloudTrailデータイベント、従来のS3バケット配信、今回追加されたCloudWatch Logs配信があります。CloudWatch Logs配信+S3 Tables連携は、構造化JSONをCloudWatch Logs Insightsで扱え、AthenaのSQL分析にもつなげられる新しい選択肢です。用途、遅延許容度、監査要件、コストを踏まえて使い分けるのがよさそうです。
参考リンク








