上級 35分 Lesson 3

CloudTrail — 証跡設計・整合性検証・リアルタイム検知

CloudTrailの証跡設計、データイベント、Insights、整合性検証、Athena連携を徹底解説

AWS CloudTrail SCS-C03 ログ Security

概論: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 ダッシュボード画面は以下のように表示されます。

CloudTrail Trail 設定


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 ObjectGetObject, 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の仕組み

  1. CloudTrailが過去90日のAPIアクティビティをベースラインとして学習
  2. 異常検知のアルゴリズムで「通常と異なる動作」を判定
  3. 一致する場合、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

推奨:本番環境ではマルチリージョンを選択。理由は:

  1. リージョン別の証跡管理は運用負荷が大きい
  2. リージョン内攻撃を見落とすリスク
# マルチリージョン証跡(推奨)
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
eventNameAPI操作名CreateUser, PutObject
resources.typeリソース種別AWS::S3::Object, AWS::IAM::User
resources.ARNリソースARNarn:aws:s3:::bucket/*
eventSourceAWSサービスec2.amazonaws.com
readOnly読み取り専用true, false
recipientAccountId実行者のアカウントID123456789012
userIdentity.principalIdIAMプリンシパルIDAIDAI…

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の前提条件

  1. AWS Organizations が有効化されていること
  2. CloudTrail委任管理者 が指定されていること
  3. 各メンバーアカウントが信頼ポリシーで承認していること

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内部APIinternal.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: 以下の設計で対応

  1. データイベント対象を限定:arn:aws:s3:::prod-bucket/* (全バケットではない)
  2. ReadWriteType を “WriteOnly” に設定:GetObject(読取)は記録しない
  3. 集約ログは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/*

さらに深掘り:推奨リソース