CloudTrail — 証跡設計・整合性検証・リアルタイム検知
CloudTrailの証跡設計、データイベント、Insights、整合性検証、Athena連携を徹底解説
概論:CloudTrailとは何か
CloudTrailは、AWSアカウントの全API呼び出しをログとして記録するサービスです。単なるログ記録ではなく、セキュリティ監査・コンプライアンス・リアルタイム脅威検知の基盤になります。
SCS-C03試験では、CloudTrailの以下のポイントが問われます:
- 証跡(Trail)設計:管理イベント vs データイベント vs Insights
- 整合性検証:ログの改ざん検知
- マルチアカウント集約:Organizations Trail
- リアルタイム検知:CloudWatch Logs / EventBridge連携
- 制約と落とし穴:イベント配信遅延、90日ローテーション、S3ライフサイクル
CloudTrail アーキテクチャ図
1. CloudTrail イベントフロー(管理 / データ / Insights → 保存・検知)
Loading diagram...
2. Organizations Trail アーキテクチャ(組織横断集約)
Loading diagram...
3. ログ整合性検証チェーン(Digest Files)
Loading diagram...
CloudTrail ダッシュボード画面は以下のように表示されます。

1. CloudTrailの3つのイベントタイプ
1.1 管理イベント(Management Events)
定義:AWS リソースの設定変更を記録するイベント。
| 特性 | 説明 |
|---|---|
| 記録対象 | IAM, EC2, S3バケットポリシー, ネットワーク設定など |
| デフォルト | CloudTrail有効化時に自動記録 |
| 保持期間 | CloudTrail標準:90日(S3に配信すれば長期保存可能) |
| スケール | 低頻度(秒単位) |
例:iam:CreateUser, ec2:RunInstances, s3:PutBucketPolicy
管理イベント単独では、誰がオブジェクトを読み取ったかは分かりません。それがデータイベントの役割です。
# 管理イベントのみを有効にした証跡作成
aws cloudtrail create-trail \
--name my-trail \
--s3-bucket-name my-bucket \
--is-multi-region-trail
1.2 データイベント(Data Events)
定義:リソース内のデータ操作を記録するイベント。追加料金が発生します。
| 対象 | イベント例 |
|---|---|
| S3 Object | GetObject, PutObject, DeleteObject |
| Lambda | 関数の実行 |
| DynamoDB | テーブルの読み書き |
| EBS | ボリュームのアクセス |
データイベントはデフォルトでOFFです。明示的に有効化する必要があります。
# S3特定バケットのデータイベントを有効化
aws cloudtrail put-event-selectors \
--trail-name my-trail \
--event-selectors \
'[
{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3:::my-bucket/*"]
}
]
}
]'
料金モデル:
- 管理イベント:最初の100,000件/月は無料、その後$2 per 100,000件
- データイベント:$0.10 per 100,000件
試験で狙われるポイント:
- データイベントは「全バケット」
arn:aws:s3:::*/*で有効化できるが、コスト爆増のリスクがある - 本番環境では対象を限定する必要がある
1.3 Insightsイベント(CloudTrail Insights)
定義:CloudTrailが異常なAPI活動を自動検知して記録する特別なイベント。
例:
- 通常は GetObject が月1回なのに、5分で1000回実行
- IAMロールへの権限追加が通常の10倍の速度
- DeleteBucket が複数のユーザーから同時実行
Insightsの仕組み:
- CloudTrailが過去90日のAPIアクティビティをベースラインとして学習
- 異常検知のアルゴリズムで「通常と異なる動作」を判定
- 一致する場合、
InsightEventログを生成
有効化:
aws cloudtrail put-insight-selectors \
--trail-name my-trail \
--insight-selectors [{"InsightType": "ApiCallRateInsight"}]
制限:
- Management Eventsのみに対応(データイベントは対象外)
- 追加料金:$0.35 per 100,000 Insights Events
使い道:
- 短期間での異常なAPIコールパターン検知
- ランサムウェア・クレデンシャルスティールの初期兆候
2. 証跡(Trail)の詳細設計
2.1 単一リージョン vs マルチリージョン
| 特性 | 単一リージョン | マルチリージョン |
|---|---|---|
| 対象 | 指定リージョンのみ | すべてのリージョン |
| 推奨 | テスト環境のみ | 本番環境・すべて |
| 作成例 | --is-multi-region-trail false | --is-multi-region-trail true |
推奨:本番環境ではマルチリージョンを選択。理由は:
- リージョン別の証跡管理は運用負荷が大きい
- リージョン内攻撃を見落とすリスク
# マルチリージョン証跡(推奨)
aws cloudtrail create-trail \
--name prod-trail \
--s3-bucket-name prod-logs \
--is-multi-region-trail
2.2 S3配信設定
CloudTrailはS3にログを配信する際、以下を守る必要があります:
# S3バケット作成
aws s3 mb s3://cloudtrail-logs-prod
# バケットポリシー(CloudTrailが書き込み可能に)
cat > policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::cloudtrail-logs-prod"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::cloudtrail-logs-prod/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket cloudtrail-logs-prod \
--policy file://policy.json
S3ライフサイクル設定例:
cat > lifecycle.json << 'EOF'
{
"Rules": [
{
"Id": "ArchiveOldLogs",
"Status": "Enabled",
"Transitions": [
{
"Days": 90,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 2555
}
}
]
}
EOF
aws s3api put-bucket-lifecycle-configuration \
--bucket cloudtrail-logs-prod \
--lifecycle-configuration file://lifecycle.json
2.3 CloudWatch Logs連携
リアルタイムアラートが必要な場合、CloudWatch Logsを経由します:
# CloudWatch Logs グループ作成
aws logs create-log-group \
--log-group-name /aws/cloudtrail/prod
# IAMロール作成(CloudTrail→CloudWatch Logs)
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role \
--role-name CloudTrailCloudWatchLogsRole \
--assume-role-policy-document file://trust-policy.json
# ロールポリシー追加
cat > logs-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:log-group:/aws/cloudtrail/*"
}
]
}
EOF
aws iam put-role-policy \
--role-name CloudTrailCloudWatchLogsRole \
--policy-name AllowCloudWatchLogs \
--policy-document file://logs-policy.json
# 証跡にCloudWatch Logs連携を追加
aws cloudtrail update-trail \
--name prod-trail \
--cloud-watch-logs-log-group-arn arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/cloudtrail/prod \
--cloud-watch-logs-role-arn arn:aws:iam::123456789012:role/CloudTrailCloudWatchLogsRole
2.4 イベントセレクタの高度なフィルタリング
CloudTrailは イベントセレクタ によって、より細かく記録対象を制御できます。
aws cloudtrail put-event-selectors \
--trail-name prod-trail \
--advanced-event-selectors \
'[
{
"Field": "eventCategory",
"Equals": ["Management"]
},
{
"Field": "resources.type",
"Equals": ["AWS::IAM::User"]
},
{
"Field": "eventName",
"NotEquals": ["GetUser", "ListUsers"]
}
]'
利用可能なフィールド:
| フィールド | 説明 | 例 |
|---|---|---|
eventCategory | イベント種別 | Management, Data, Insight |
eventName | API操作名 | CreateUser, PutObject |
resources.type | リソース種別 | AWS::S3::Object, AWS::IAM::User |
resources.ARN | リソースARN | arn:aws:s3:::bucket/* |
eventSource | AWSサービス | ec2.amazonaws.com |
readOnly | 読み取り専用 | true, false |
recipientAccountId | 実行者のアカウントID | 123456789012 |
userIdentity.principalId | IAMプリンシパルID | AIDAI… |
3. 整合性検証(Digest Files)
CloudTrailは ダイジェストファイル を生成し、ログの改ざんを検知できます。
3.1 ダイジェストファイルの仕組み
ダイジェストチェーン:
- 時刻1: ログA → SHA256ハッシュ → Digest1 (A)
- 時刻2: ログB + Digest1 → SHA256ハッシュ → Digest2 (B, Digest1)
- 時刻3: ログC + Digest2 → SHA256ハッシュ → Digest3 (C, Digest2)
チェーンで改ざんを検知可能
3.2 整合性検証の実装
# ダイジェストファイルのダウンロード
aws s3 cp s3://cloudtrail-logs-prod/AWSLogs/123456789012/CloudTrail/ap-northeast-1/2026/04/27/ . --recursive
# Python でダイジェスト検証
cat > verify_cloudtrail.py << 'EOF'
import json
import hashlib
import hmac
def verify_digest(digest_file, previous_digest=None):
with open(digest_file, 'r') as f:
digest_data = json.load(f)
# チェーンのハッシュを計算
chain_hash = digest_data.get('chainHash')
digest_hash = digest_data.get('digestHash')
log_hashes = digest_data.get('logFiles', [])
# 改ざん検知ロジック
if previous_digest:
if chain_hash != previous_digest['digestHash']:
print("WARNING: Chain integrity broken!")
return False
print(f"Digest verified: {digest_hash}")
return True
# 使用例
verify_digest('AWSLogs/.../digest.json')
EOF
python verify_cloudtrail.py
CLI での検証:
# AWS管理ツール(公式)
aws cloudtrail validate-logs \
--trail-name prod-trail \
--start-time 2026-04-27T00:00:00Z \
--end-time 2026-04-28T00:00:00Z
結果の見方:
{
"ValidationStatus": "Valid",
"DigestValidationSucceeded": true,
"LogValidationSucceeded": true,
"LogsChecked": 150,
"LogsFound": 150,
"LogsHashMatched": 150,
"LogsInvalid": 0
}
4. マルチアカウント集約(Organizations Trail)
複数のAWSアカウントを一元管理する場合、Organizations Trailを使用します。
4.1 Organizations Trailの前提条件
- AWS Organizations が有効化されていること
- CloudTrail委任管理者 が指定されていること
- 各メンバーアカウントが信頼ポリシーで承認していること
4.2 Organizations Trailの設定
# (組織の管理アカウントで実行)
# 1. CloudTrail委任管理者を登録
aws organizations register-delegated-administrator \
--account-id 111111111111 \
--service-principal cloudtrail.amazonaws.com
# 2. 委任管理者アカウントで組織証跡を作成
# (アカウント111111111111で実行)
# S3バケット作成(すべてのアカウントが書き込み可能に)
aws s3 mb s3://org-cloudtrail-logs
cat > org-bucket-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::org-cloudtrail-logs"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::org-cloudtrail-logs/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
},
{
"Sid": "AllowOrganizationAccounts",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::org-cloudtrail-logs/*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-xxxxxxxxxx"
}
}
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket org-cloudtrail-logs \
--policy file://org-bucket-policy.json
# 3. 組織証跡を作成
aws cloudtrail create-trail \
--name org-trail \
--s3-bucket-name org-cloudtrail-logs \
--is-multi-region-trail \
--is-organization-trail
4.3 組織証跡のメリット
| メリット | 説明 |
|---|---|
| 一元管理 | すべてのメンバーアカウントのログを1つの証跡で集約 |
| 自動対応 | 新規アカウント追加時、自動的にログ記録開始 |
| コスト最適化 | 各アカウント個別設定の手間が不要 |
| 監査対応 | 組織全体のログを単一S3バケットで保管 |
5. できないこと・制約
5.1 イベント配信遅延
CloudTrailのイベント配信はリアルタイムではありません。
| 配信先 | 遅延時間 |
|---|---|
| S3 | 通常5-15分、最大1時間 |
| CloudWatch Logs | 通常5分、最大15分 |
| EventBridge | 通常1-2分 |
含意:
- 侵入検知には完全なリアルタイム性が必要なため、GuardDuty + Security Hub との併用推奨
- リアルタイム性が必要な場合は、CloudWatch Events(EventBridge)で検知→Lambda→アラート
5.2 ログ保持期間
CloudTrail標準保持:90日(自動削除)
↓
S3 + ライフサイクル設定で長期保存(推奨)
↓
Athena / QuickSight での分析
試験で狙われるポイント:
Q: CloudTrailログを2年間保存する必要があります。どうしますか? A: S3にログを配信し、S3ライフサイクルで保持期間を2年に設定します。 (CloudTrailの90日制限を超える場合は、S3が必須)
5.3 クォータ・制限
| 制限 | 値 |
|---|---|
| 証跡あたりのイベントセレクタ | 最大250個 |
| S3配信(デフォルト) | 1リージョンあたり4Mbps |
| CloudWatch Logs配信 | 1000 log events/sec per account |
| Organizations Trail数 | 1アカウントあたり最大5個 |
| APIレート制限 | CreateTrail: 5req/sec |
制約の回避方法:
- 複数のCloudWatch Logsを使用(分散書き込み)
- S3のマルチパートアップロードを有効化
5.4 データイベント記録の制限
# これはできない:全リソースのデータイベント有効化(本番環境)
aws cloudtrail put-event-selectors \
--trail-name prod-trail \
--event-selectors '[{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
]
}]'
# 理由:コストが数万円/月に跳ね上がる、S3書き込み遅延増加
5.5 その他の制限
- VPC Endpoint経由のAPI呼び出し:CloudTrailに記録される場合とされない場合がある
- AWS内部API:
internal.amazonaws.comへのコールは記録されない - CloudFront:CloudTrailでは記録されない(CloudFront Access Logsを使用)
6. ユースケース別の設計
6.1 ユースケース1:不正アクセス調査
シナリオ:IAMユーザー alice のアクセスキーが盗まれた可能性がある。
設計:
# 1. CloudWatch Logs にフィルター設定(アラート)
aws logs put-metric-filter \
--log-group-name /aws/cloudtrail/prod \
--filter-name UnauthorizedAPICalls \
--filter-pattern '{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode = "AccessDenied*") }' \
--metric-transformations \
metricName=UnauthorizedAPICallsMetric,metricNamespace=CloudTrailMetrics,metricValue=1
# 2. Athena で該当期間のログを検索
cat > query.sql << 'EOF'
SELECT
eventTime,
eventName,
userIdentity.principalId,
sourceIPAddress,
userAgent,
errorCode,
errorMessage
FROM cloudtrail_logs
WHERE userIdentity.principalId = 'AIDAI...'
AND eventTime BETWEEN '2026-04-27T00:00:00Z' AND '2026-04-28T00:00:00Z'
AND eventName NOT LIKE 'Get%'
ORDER BY eventTime DESC;
EOF
# 3. EventBridge で自動応答
cat > rule.json << 'EOF'
{
"Name": "AutoResponseToSuspiciousActivity",
"EventPattern": {
"source": ["aws.cloudtrail"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"errorCode": ["AccessDenied", "UnauthorizedOperation"],
"sourceIPAddress": ["203.0.113.0/24"]
}
},
"State": "ENABLED",
"Targets": [
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:function:DisableUserAccessKey",
"RoleArn": "arn:aws:iam::123456789012:role/EventBridgeLambdaRole"
}
]
}
EOF
aws events put-rule --cli-input-json file://rule.json
6.2 ユースケース2:コンプライアンス監査
シナリオ:金融機関の規制要件で「すべてのIAM変更をタイムスタンプ付きで記録」。
設計:
# 1. IAM操作のみを記録するイベントセレクタ
aws cloudtrail put-advanced-event-selectors \
--trail-name audit-trail \
--advanced-event-selectors \
'[
{
"Field": "eventSource",
"Equals": ["iam.amazonaws.com"]
},
{
"Field": "readOnly",
"Equals": ["false"]
}
]'
# 2. S3にCOPYロック設定(改ざん防止)
aws s3api put-object-lock-configuration \
--bucket cloudtrail-logs-audit \
--object-lock-configuration '{"ObjectLockEnabled": "Enabled", "Rule": {"DefaultRetention": {"Mode": "GOVERNANCE", "Days": 2555}}}'
# 3. Athena で定期レポート生成
cat > compliance_report.sql << 'EOF'
SELECT
eventTime::date as audit_date,
eventName,
userIdentity.principalId as user,
requestParameters,
responseElements,
sourceIPAddress
FROM cloudtrail_logs
WHERE eventSource = 'iam.amazonaws.com'
AND readOnly = false
AND eventTime >= current_date - interval '90' day
ORDER BY eventTime DESC;
EOF
6.3 ユースケース3:リアルタイムアラート
シナリオ:RootアカウントでのAPI実行、特定セキュリティグループの削除を即座に検知。
設計:
# 1. CloudWatch Logs メトリクスフィルター
aws logs put-metric-filter \
--log-group-name /aws/cloudtrail/prod \
--filter-name RootAccountUsage \
--filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
--metric-transformations metricName=RootAccountUsageCount,metricNamespace=SecurityAlerts,metricValue=1
# 2. アラーム設定
aws cloudwatch put-metric-alarm \
--alarm-name RootAccountUsageAlert \
--alarm-description "Alert when Root account is used" \
--metric-name RootAccountUsageCount \
--namespace SecurityAlerts \
--statistic Sum \
--period 60 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--alarm-actions arn:aws:sns:ap-northeast-1:123456789012:SecurityAlerts
# 3. EventBridge で Security Hub へ送信
aws events put-rule \
--name "SendCloudTrailToSecurityHub" \
--event-pattern '{
"source": ["aws.cloudtrail"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ec2.amazonaws.com"],
"eventName": ["DeleteSecurityGroup"]
}
}'
aws events put-targets \
--rule "SendCloudTrailToSecurityHub" \
--targets "Id"="1","Arn"="arn:aws:securityhub:ap-northeast-1:123456789012:hub/default"
6.4 ユースケース4:マルチアカウント集約分析
シナリオ:10個の本番アカウント+開発アカウント10個の全ログを一元管理。
設計:
# 1. Organizations Trail で全アカウント集約(前述)
# 2. Athena パーティション設定(パフォーマンス最適化)
cat > partition_projection.sql << 'EOF'
CREATE EXTERNAL TABLE IF NOT EXISTS cloudtrail_logs_partitioned (
eventversion STRING,
useridentity STRUCT<
type: STRING,
principalid: STRING,
arn: STRING,
accountid: STRING,
invokedby: STRING,
accesskeyid: STRING,
userName: STRING,
sessioncontext: STRUCT<
attributes: STRUCT<
mfaauthenticated: STRING,
creationdate: STRING>,
sessionissuer: STRUCT<
type: STRING,
principalId: STRING,
arn: STRING,
accountId: STRING,
userName: 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,
resources ARRAY<STRUCT<
ARN: STRING,
accountId: STRING,
type: STRING>>,
eventtype STRING,
recipientaccountid STRING,
sharedEventID STRING,
vpcendpointid STRING
)
PARTITIONED BY (
region STRING,
year STRING,
month STRING,
day STRING,
account_id STRING
)
STORED AS JSON
LOCATION 's3://org-cloudtrail-logs/'
TBLPROPERTIES (
'projection.enabled' = 'true',
'projection.region.type' = 'enum',
'projection.region.values' = 'us-east-1,ap-northeast-1,eu-west-1',
'projection.year.type' = 'integer',
'projection.year.range' = '2020,2030',
'projection.month.type' = 'integer',
'projection.month.range' = '1,12',
'projection.month.digits' = '2',
'projection.day.type' = 'integer',
'projection.day.range' = '1,31',
'projection.day.digits' = '2',
'projection.account_id.type' = 'enum',
'projection.account_id.values' = '111111111111,222222222222,...',
's3select.sql.filter.json.alias' = 'true'
)
EOF
# 3. クロスアカウント分析クエリ
cat > cross_account_analysis.sql << 'EOF'
SELECT
recipientaccountid AS account,
region,
eventname,
COUNT(*) AS event_count
FROM cloudtrail_logs_partitioned
WHERE year = '2026'
AND month = '04'
AND eventtype = 'AwsApiCall'
GROUP BY
recipientaccountid,
region,
eventname
ORDER BY event_count DESC
LIMIT 50;
EOF
7. ベストプラクティス
7.1 証跡の保護(Defense in Depth)
# 1. S3 バージョニング有効化(誤削除復旧)
aws s3api put-bucket-versioning \
--bucket cloudtrail-logs \
--versioning-configuration Status=Enabled
# 2. S3 MFA Delete 有効化(root権限でも削除不可)
aws s3api put-bucket-versioning \
--bucket cloudtrail-logs \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::123456789012:mfa/root-account 123456"
# 3. S3 Object Lock (WORM) 設定
aws s3api put-object-lock-configuration \
--bucket cloudtrail-logs \
--object-lock-configuration \
'{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 2555
}
}
}'
# 4. CloudTrail ログ検証有効化(ダイジェスト自動生成)
aws cloudtrail update-trail \
--name prod-trail \
--enable-log-file-validation
# 5. CloudTrail 削除不可設定(CLI削除を困難に)
cat > prevent-trail-deletion.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PreventCloudTrailDeletion",
"Effect": "Deny",
"Principal": "*",
"Action": [
"cloudtrail:DeleteTrail",
"cloudtrail:StopLogging",
"cloudtrail:UpdateTrail"
],
"Resource": "arn:aws:cloudtrail:*:123456789012:trail/prod-trail",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/SecurityAdmin"
}
}
}
]
}
EOF
7.2 整合性検証のベストプラクティス
# 1. 定期的な検証スクリプト
cat > daily_validation.sh << 'EOF'
#!/bin/bash
AWS_ACCOUNT=123456789012
TRAIL_NAME=prod-trail
START_TIME=$(date -u -d '1 day ago' +'%Y-%m-%dT%H:%M:%SZ')
END_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
aws cloudtrail validate-logs \
--trail-name $TRAIL_NAME \
--start-time $START_TIME \
--end-time $END_TIME \
| jq '.ValidationStatus'
EOF
# 2. cron で毎日実行
echo "0 2 * * * /root/daily_validation.sh >> /var/log/cloudtrail-validation.log 2>&1" | crontab -
# 3. 検証失敗時にアラート
# CloudWatch ログで検証失敗を検知 → SNS通知
7.3 ログ集約アーキテクチャ
┌─────────────────────────────────────────────────────────────┐
│ Organizations Trail (Management Account) │
└──────────────────────────────┬──────────────────────────────┘
│
┌──────────▼──────────┐
│ S3 CloudTrail Logs │
│ (Aggregation Bucket)│
└──────────┬──────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Athena │ │EventBridge │CloudWatch
│ (Query) │ │(Real-time) │(Metrics)
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│QuickSight │Lambda │ │Alarms │
│(Report) │(Auto │ │(SNS) │
│ │Response) │ │
└─────────┘ └────────┘ └────────┘
実装:
1. Organizations Trail で全アカウント集約
2. S3 に配信(ライフサイクル:90日→Glacier→delete)
3. Athena でアドホック分析&定期レポート
4. EventBridge で異常検知→Lambda自動対応
5. CloudWatch Logs で実時間メトリクス→Alarms
8. 他サービスとの連携パターン
8.1 CloudWatch Logs 連携
目的:CloudTrail ログをリアルタイムに検索・フィルター。
# 1. CloudTrail → CloudWatch Logs
# (前述の設定参照)
# 2. CloudWatch Logs フィルター設定例
# 高権限操作を検知
aws logs put-metric-filter \
--log-group-name /aws/cloudtrail/prod \
--filter-name HighPrivilegeOperations \
--filter-pattern '[eventName = "CreateAccessKey" || eventName = "AttachUserPolicy" || eventName = "PutUserPolicy"]' \
--metric-transformations \
metricName=HighPrivOps,metricNamespace=Security,metricValue=1
# 3. クエリ実行
aws logs start-query \
--log-group-name /aws/cloudtrail/prod \
--start-time $(date -d '1 hour ago' +%s) \
--end-time $(date +%s) \
--query-string 'fields @timestamp, eventName, userIdentity.principalId | filter eventName like /Create|Delete|Attach/'
8.2 EventBridge 連携
目的:特定のCloudTrailイベントをキャッチして自動対応。
# イベントパターン例:RootでのIAM操作
cat > eventbridge-rule.json << 'EOF'
{
"Name": "RootIAMOperationDetection",
"EventPattern": {
"source": ["aws.cloudtrail"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["iam.amazonaws.com"],
"userIdentity": {
"type": ["Root"]
}
}
},
"Targets": [
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:function:AlertSecurityTeam",
"RoleArn": "arn:aws:iam::123456789012:role/EventBridgeLambdaRole"
},
{
"Arn": "arn:aws:sns:ap-northeast-1:123456789012:SecurityAlerts"
}
]
}
EOF
aws events put-rule --cli-input-json file://eventbridge-rule.json
8.3 Athena 連携(ログ分析)
-- 例1:日別のAPI実行数ランキング
SELECT
date_format(from_iso8601_timestamp(eventtime), '%Y-%m-%d') as date,
eventname,
count(*) as count
FROM cloudtrail_logs
WHERE year = '2026' AND month = '04'
GROUP BY 1, 2
ORDER BY date DESC, count DESC;
-- 例2:失敗したAPI呼び出し(セキュリティ侵害の兆候)
SELECT
eventtime,
eventname,
errorcode,
sourceipaddress,
useragent,
useridentity.principalid
FROM cloudtrail_logs
WHERE errorcode IS NOT NULL
AND errorcode NOT IN ('AuthFailure', 'InvalidParameterValue')
AND eventtime >= format_datetime(current_timestamp - interval '24' hour, 'yyyy-MM-dd''T''HH:mm:ss''Z')
ORDER BY eventtime DESC;
-- 例3:異なるIPアドレスからのアクセス(クレデンシャルスティール検知)
SELECT
useridentity.principalid,
sourceipaddress,
count(*) as api_count,
approx_distinct(eventname) as unique_events
FROM cloudtrail_logs
WHERE year = '2026' AND month = '04'
GROUP BY 1, 2
HAVING count(*) > 50
ORDER BY api_count DESC;
8.4 Security Hub 連携
# CloudTrail ログをSecurity Hubに統合
aws securityhub update-findings \
--findings '[{
"ProductArn": "arn:aws:securityhub:ap-northeast-1:123456789012:product/123456789012/default",
"Types": ["Effects/Data Exposure/CloudTrail Logs"],
"Title": "Unusual CloudTrail Activity Detected",
"Severity": {"Label": "MEDIUM"},
"Resources": [{
"Type": "AwsCloudTrail",
"Id": "arn:aws:cloudtrail:ap-northeast-1:123456789012:trail/prod-trail",
"Region": "ap-northeast-1"
}]
}]'
8.5 S3 + Lambda 連携(自動ログ処理)
# Lambda関数:CloudTrail ログをS3に保存→自動パース
cat > process-cloudtrail.py << 'EOF'
import json
import gzip
import boto3
import base64
from datetime import datetime
s3 = boto3.client('s3')
cloudwatch = boto3.client('cloudwatch')
def lambda_handler(event, context):
# S3イベント通知を処理
bucket = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
# CloudTrailログファイルをダウンロード
response = s3.get_object(Bucket=bucket, Key=key)
# gzip解凍
with gzip.GzipFile(fileobj=response['Body']) as gzipfile:
logs = json.loads(gzipfile.read())
# イベント分析
for record in logs.get('Records', []):
event_name = record.get('eventName')
error_code = record.get('errorCode')
# メトリクス送信
if error_code:
cloudwatch.put_metric_data(
Namespace='CloudTrailAnalysis',
MetricData=[
{
'MetricName': f'Error-{error_code}',
'Value': 1,
'Timestamp': datetime.utcnow()
}
]
)
return {'statusCode': 200, 'body': f'Processed {len(logs.get("Records", []))} events'}
EOF
# Lambda トリガー設定
aws lambda create-event-source-mapping \
--event-source-arn arn:aws:s3:::cloudtrail-logs \
--function-name ProcessCloudTrailLogs \
--enabled
9. 試験で狙われるポイント(SCS-C03)
9.1 実装パターン問題
Q: 本番環境で大量のデータイベント(S3読み取り)をCloudTrailで記録したい。 パフォーマンスと コストを両立させるには?
A: 以下の設計で対応
- データイベント対象を限定:
arn:aws:s3:::prod-bucket/*(全バケットではない) - ReadWriteType を “WriteOnly” に設定:GetObject(読取)は記録しない
- 集約ログはS3→Athenaで事後分析(リアルタイムは別途EventBridge)
9.2 整合性検証問題
Q: CloudTrailログが改ざんされたかどうかを検知するには?
A:
--enable-log-file-validationで有効化aws cloudtrail validate-logsで検証- ダイジェストファイルのハッシュチェーンで改ざん検知
9.3 ログ配信遅延問題
Q: リアルタイムで不正アクセスを検知したい。CloudTrailだけで対応できる?
A: いいえ
- CloudTrailは最大1時間の遅延
- リアルタイムには EventBridge + CloudWatch Logs + GuardDuty の併用必須
9.4 マルチアカウント設計問題
Q: 5つの本番アカウント+20の開発アカウントのCloudTrailログを一元管理したい。 最小限のオーバーヘッドで実現するには?
A: Organizations Trail
- 1つの証跡ですべてのアカウントを集約
- 新規アカウント追加時に自動対応
- 単一S3バケットで保管・管理
10. まとめ:CloudTrail設計チェックリスト
本番環境CloudTrail設計チェックリスト:
☐ マルチリージョン証跡を設定した
☐ S3に配信し、ライフサイクル設定で長期保存
☐ ダイジェスト検証 (--enable-log-file-validation) を有効化
☐ S3 Object Lock (WORM) で改ざん防止
☐ CloudWatch Logs に配信してリアルタイム監視
☐ メトリクスフィルター設定:Root利用、IAM変更、セキュリティグループ操作
☐ EventBridge で異常イベント → Lambda自動対応
☐ Athena パーティション設定で高速クエリ
☐ データイベント対象を限定(コスト管理)
☐ Organizations Trail で複数アカウント集約
☐ CloudWatch Logs → Security Hub で統合監視
☐ ダイジェスト検証を定期実行(cron)
☐ アラーム設定:Root使用、大量APIコール、エラー多発
Organizations環境の場合:
☐ 委任管理者アカウントを指定
☐ 各メンバーアカウントのS3バケットポリシーを確認
☐ Organizations Trail の is-organization-trail = true
参考:トラブルシューティング
# CloudTrail が ログ配信に失敗している場合
# 1. 証跡の状態確認
aws cloudtrail describe-trails --trail-name prod-trail
# 2. 最後のログ配信時刻確認
aws cloudtrail get-trail-status --name prod-trail | jq '.LatestDeliveryTime'
# 3. S3バケットポリシー確認
aws s3api get-bucket-policy --bucket cloudtrail-logs
# 4. CloudWatch Logs でエラーを確認
aws logs tail /aws/cloudtrail/prod --follow
# 5. IAM権限確認
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/CloudTrailRole \
--action-names cloudtrail:PutEvents \
--resource-arns arn:aws:s3:::cloudtrail-logs/*
さらに深掘り:推奨リソース
- AWS CloudTrail User Guide
- CloudTrail Event Reference
- AWS Security Best Practices
- SCS-C03 公式試験ガイド(Udemy/A Cloud Guru等)