SOC2審査でCloudTrail・Configに3ヶ月ハマった話。本当に動く監査設計パターン

CloudTrail・AWS Configの監査設計で地獄を見た実体験。S3ログの罠、コスト爆発、運用できない設定の失敗から学んだ実装パターンを本音で解説します。

CloudTrail・Config地獄への入口

先日、うちのチームがSOC2 Type II認証を受けることになって、その過程で CloudTrail と AWS Config の監査設計に本気でハマりました。正直、「ログ記録して終わり」くらいに考えてたんですけど、現実はそんなに甘くなかった。

プロジェクト初期段階で経理部門と監査人から「これまでのログどこにあるの?」と聞かれて、あ、これマジでヤバいやつだなって気づいたんです。CloudTrail は有効化されてたんですが、ログを S3 に溜めてるだけで、実際に検索・分析できる状態じゃなかった。Config に至っては、「え、これ何?」状態。3ヶ月間、まじで地獄でした。

この記事では、その失敗から学んだことを共有します。単なる「設定方法」じゃなくて、「本当に運用できる」監査設計のパターンを、実装コード付きで書きます。

CloudTrail の地獄:「ログがあるだけ」の罠

最初の落とし穴は、CloudTrail ログが S3 に溜まってるだけで、実際に検索できてなかったことです。監査人は「特定の日時に IAM ユーザーが何をしたか」を即座に答えてほしい。でも S3 の JSON ファイルをゴリゴリ探すわけにはいかない。

僕たちが取った対策は、CloudTrail ログを Athena で検索可能にすることでした。CloudTrail Insights も有効化して、異常なアクティビティも自動検知する。ただし、これには落とし穴がある。CloudTrail ログって量がハンパじゃないんです。本番環境だと 1 日で数 GB。S3 ストレージ料金だけで月 5 万円くらい吹っ飛ぶ可能性もある。

実装としては、こんな感じ:

# CloudFormation or CDK
CloudTrailBucket:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: !Sub 'cloudtrail-logs-${AWS::AccountId}'
    VersioningConfiguration:
      Status: Enabled
    LifecycleConfiguration:
      Rules:
        - Id: TransitionToIA
          Status: Enabled
          Transitions:
            - TransitionInDays: 30
              StorageClass: STANDARD_IA
            - TransitionInDays: 90
              StorageClass: GLACIER
        - Id: ExpireOldLogs
          Status: Enabled
          ExpirationInDays: 2555  # 7年保持

CloudTrail:
  Type: AWS::CloudTrail::Trail
  Properties:
    IsLogging: true
    S3BucketName: !Ref CloudTrailBucket
    IncludeGlobalServiceEvents: true
    IsMultiRegionTrail: true
    EnableLogFileValidation: true
    EventSelectors:
      - ReadWriteType: All
        IncludeManagementEvents: true
        DataResources:
          - Type: 'AWS::S3::Object'
            Values:
              - 'arn:aws:s3:::*/'
          - Type: 'AWS::Lambda::Function'
            Values:
              - 'arn:aws:lambda:*:*:function/*'

重要なのは EventSelectors のデータリソース指定です。これを書かないと、API コールだけ記録されて、S3 や Lambda アクセスのログが落ちます。監査人に「このファイルいつ誰が変更した?」と聞かれても答えられなくなる。

そしてログファイル検証(EnableLogFileValidation)。これが有効になってると、ログが改ざんされたかどうかを CloudTrail が自動検証してくれます。SOC2 審査では「ログの完全性」が重要だから、これは必須。

Athena での検索も地味に重要です。CloudTrail ログが Athena パーティション対応になってないと時間がかかる。別途 Glue Crawler でメタデータを自動生成するか、Athena の自動パーティション検出を有効にしましょう。

-- Athena で CloudTrail ログ検索
SELECT
  eventtime,
  eventname,
  useridentity.principalid,
  sourceipaddress,
  useragent,
  requestparameters
FROM cloudtrail_logs
WHERE
  eventtime >= '2026-06-01'
  AND eventname IN ('PutObject', 'DeleteObject', 'ModifyDBInstance')
  AND year = 2026
  AND month = 6
  AND day >= 1
ORDER BY eventtime DESC

このクエリで「6 月 1 日以降の S3・RDS 変更履歴」が 10 秒で返ってくるようになります。ログがあるだけの状態からここまで来るのに、実は 1~2 週間かかったんですよ。

AWS Config:「何が変わったか」を追える設計

CloudTrail が「誰が何をしたか」を記録するなら、Config は「リソースの状態がどう変わったか」を記録します。監査人は「このセキュリティグループのルール、いつどうやって変わったの?」という質問をしてくる。そこで Config の出番です。

ただし、Config も放置してると地雷だらけです。僕たちの場合、Config ルールを作ったはいいけど、アラートが週 500 件くらい来てて、もう誰も見てなかった状態でした。正直に言うと、通知が多すぎて逆に信頼度が落ちちゃったんですよね。

Config ルールの「推奨設定」って環境によって合わない場合が多い。例えば encrypted-volumes ルール。全 EBS ボリュームが暗号化されてることを要求します。でも開発環境では不要だったり、デフォルトで暗号化されてるリージョンもある。

僕たちが最終的に落ち着いたのは、環境ごとに Config ルールを分ける設計:

// CDK example
import * as config from 'aws-cdk-lib/aws-config';

const productionRules = [
  'encrypted-volumes',
  'root-account-mfa-enabled',
  'cloudtrail-enabled',
  'multi-region-cloudtrail-enabled',
  'mfa-enabled-for-iam-console-access',
  'iam-policy-no-statements-with-admin-access',
  's3-default-encryption-enabled',
  'alb-http-to-https-redirection-check',
];

const developmentRules = [
  'cloudtrail-enabled',  // 本番ほど厳しくない
  'root-account-mfa-enabled',
];

const environment = process.env.ENVIRONMENT || 'development';
const activeRules = environment === 'production' ? productionRules : developmentRules;

activeRules.forEach((ruleName) => {
  new config.ManagedRule(this, ruleName, {
    identifier: config.ManagedRuleIdentifiers[ruleName],
    ruleScope: config.RuleScope.fromResource(
      config.ResourceType.S3_BUCKET,
      config.ResourceType.EC2_SECURITY_GROUP
    ),
  });
});

重要なのは、Config ルールをただ有効化するんじゃなくて、「何が目的か」を明確にすることです。SOC2 では特にデータセキュリティとアクセス制御が問われるから、S3・IAM・ネットワークに集中するのが正解だと気づきました。

そして Config Aggregator を使って、マルチアカウント・マルチリージョンの状態を一元管理します:

Aggregator:
  Type: AWS::Config::ConfigurationAggregator
  Properties:
    ConfigurationAggregatorName: prod-aggregator
    AccountAggregationSources:
      - AllAwsRegions: true
        AwsRegions:
          - us-east-1
          - ap-northeast-1
        AccountIds:
          - '123456789012'  # 本番アカウント
          - '234567890123'  # ステージングアカウント

コスト地獄:CloudTrail と Config の予想外の請求

これが本当にキツかった。CloudTrail は API コール 1 件ごとにログを記録するんで、本番環境だと 1 日で数百万件。S3 ストレージ + Athena クエリで月 10 万円以上吹っ飛びます。

項目費用(月)削減後削減率
CloudTrail(Management Events)8,000円4,000円50%
CloudTrail(Data Events)45,000円12,000円73%
S3 ストレージ(全体)32,000円8,000円75%
Athena クエリ25,000円6,000円76%
合計110,000円30,000円73%

コスト削減のためにやったこと、まず Data Events を絞る必要があります。データイベント(S3・Lambda アクセス)はめちゃくちゃ量が多いから、必要なバケット・関数だけに限定しましょう:

EventSelectors:
  - ReadWriteType: All
    DataResources:
      - Type: 'AWS::S3::Object'
        Values:
          - 'arn:aws:s3:::prod-database-bucket/*'  # 本番DBダンプだけ
          - 'arn:aws:s3:::secrets-bucket/*'
      - Type: 'AWS::Lambda::Function'
        Values:
          - 'arn:aws:lambda:ap-northeast-1:123456789012:function:payment-*'

次に S3 ストレージのライフサイクル設計。最初の 30 日は STANDARD で Athena で検索できるように、その後 GLACIER に移動。2555 日(7 年)で削除:

{
  "Rules": [
    {
      "Id": "ArchiveCloudTrailLogs",
      "Filter": { "Prefix": "AWSLogs/" },
      "Status": "Enabled",
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER"
        }
      ],
      "Expiration": {
        "Days": 2555
      }
    }
  ]
}

そして Config のアグリゲータ化で重複削減。マルチアカウント環境だと、各アカウント個別に Config を走らせるより、Aggregator で集約した方が結果的に安い。同じリソースを複数回評価しなくて済むから。

結果として、月 15 万円かかってた CloudTrail・Config 関連費用を月 4 万円まで削減できました。

監査体制の設計:「ログがあるだけ」から「検索できる」へ

CloudTrail と Config を整備しても、実際に監査人が「3 月 15 日の IAM ユーザー変更履歴」と言ってきたときに 2 時間かかるなら、それは運用できてません。

そこで僕たちが作ったのが、簡単な監査ダッシュボード。QuickSight で CloudTrail・Config ログを可視化しました。こういうアーキテクチャです:

graph TB
    subgraph "ログ収集層"
        CT["CloudTrail
        (MultiRegion)"]
        CFG["AWS Config
        (Aggregator)"]
        LOGS["VPC FlowLogs
        (S3)"]
    end

    subgraph "ストレージ層"
        S3["S3
        (LifecyclePolicy)"]
    end

    subgraph "検索・分析層"
        ATH["Amazon Athena
        (Glue Catalog)"]
        QL["Amazon QLDB
        (改ざん検知)"]
    end

    subgraph "可視化層"
        QS["Amazon QuickSight
        (監査ダッシュボード)"]
        CW["CloudWatch
        (アラート)"]
    end

    CT --> S3
    CFG --> S3
    LOGS --> S3
    S3 --> ATH
    S3 --> QL
    ATH --> QS
    QL --> CW
    QS --> CW

    style CT fill:#ff9900
    style CFG fill:#ff9900
    style LOGS fill:#ff9900
    style S3 fill:#569a31
    style ATH fill:#1f4788
    style QL fill:#1f4788
    style QS fill:#37475a
    style CW fill:#37475a

QuickSight からは、こんなクエリで JSON データを直接検索できるようにしました:

WITH cloudtrail_events AS (
  SELECT
    eventtime,
    eventname,
    json_extract_scalar(useridentity, '$.principalId') AS principal_id,
    json_extract_scalar(requestparameters, '$.roleName') AS role_name,
    sourceipaddress,
    useragent
  FROM cloudtrail_logs
  WHERE
    year = 2026
    AND month = 6
    AND eventname IN ('CreateRole', 'PutRolePolicy', 'AttachRolePolicy')
)
SELECT
  eventtime,
  eventname,
  principal_id,
  role_name,
  sourceipaddress,
  CASE
    WHEN principal_id LIKE '%.iam.amazonaws.com' THEN 'Service Role'
    WHEN principal_id LIKE 'AIDAI%' THEN 'IAM User'
    ELSE 'Unknown'
  END AS principal_type
FROM cloudtrail_events
ORDER BY eventtime DESC

監査人がこのダッシュボードを使えば、特定のユーザーやロールの変更履歴を 30 秒で答えられます。これが「本当に運用できる」監査設計だと痛感しました。

Config と CloudTrail の連携:変更検知の自動化

正直、Config ルールだけだと「何が違反してるか」は分かるけど、「いつ違反になったか」までは見えにくいです。CloudTrail と組み合わせて初めて “誰がいつどうやって違反を作ったか” が追える。

マルチアカウント環境での実装パターンを書きます:

// CDK: Config が違反を検知したら SNS で通知
import * as config from 'aws-cdk-lib/aws-config';
import * as sns from 'aws-cdk-lib/aws-sns';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';

const complianceTopic = new sns.Topic(this, 'ConfigComplianceTopic', {
  displayName: 'AWS Config Compliance Alerts',
});

const rule = new config.CloudFormationStackDriftDetectionCheck(this, 'StackDriftCheck');

const eventRule = new events.Rule(this, 'ConfigComplianceEventRule', {
  eventPattern: {
    source: ['aws.config'],
    detailType: ['Config Rules – Compliance Change'],
    detail: {
      messageType: ['ComplianceChangeNotification'],
      newEvaluationResult: {
        complianceType: ['NON_COMPLIANT'],
      },
    },
  },
});

eventRule.addTarget(new targets.SnsTopic(complianceTopic));

この SNS 通知を受け取って、Lambda で CloudTrail を検索して犯人を特定する、みたいな自動化も可能です。「誰が・何を・いつ」追える状態を本番化するまでに 3 ヶ月はかかると思った方がいいですよ。

CloudTrail Insights:異常検知の落とし穴

CloudTrail Insights は「異常なアクティビティを自動検知」という触れ込みなんですが、現実はかなり False Positive が多いです。

僕たちの場合:

  • 月曜朝に全リージョン一斉デプロイすると「異常検知」される
  • 決算期に AWS Support に大量問い合わせすると「異常検知」される
  • バッチ処理が大量 S3 PutObject すると「異常検知」される

ホワイトリスト機能がないから、すぐにアラート疲れになります。今の僕の推奨は「Insights は参考程度で、本気の異常検知は GuardDuty 連携に任せる」です。

SOC2 審査で実際に聞かれたこと

ここが実践的かと思います。監査人は「ああ見えてもめちゃくちゃ細かい」ので、本当のチェックリストを共有します:

  • 「CloudTrail ログファイル検証が有効か」→ 有効化してない場合、ログ改ざんの可能性を指摘される
  • 「CloudTrail で Management Events と Data Events が分かれてるか」→ 分かれてないと「何が変わったか不明」と指摘される
  • 「Config ルール評価が日次で走ってるか」→ 月次では「遅い」と言われる
  • 「Config 評価失敗時の通知フロー」→ ただ評価が失敗するだけでは駄目。誰かが気づいて対応する仕組みが必須
  • 「ログ保持期間」→ 2555 日(7 年)以上が目安。業界によって異なる

正直、これらをゼロから実装するのは 2~3 ヶ月はかかります。

まとめ

  1. CloudTrail だけでは足りない:ログがあるだけじゃ監査に耐えられない。Athena で検索できる状態までセットアップが必須。ログファイル検証も有効化して改ざん対策を

  2. Config ルールは環境ごとに分ける:推奨設定をそのまま使うと False Positive 地獄。本番・ステージング・開発で分けて、必要な項目に絞る

  3. マルチアカウント・マルチリージョンは Aggregator で一元化:個別管理だと運用が死ぬ。CloudTrail は MultiRegion で、Config は Aggregator で。コスト削減にもなる

  4. コストは LifecyclePolicy で制御:30~90 日で階級移動させて、GLACIER に逃す。ただ検索用に STANDARD の領域は残す

  5. 監査ダッシュボードを用意しないと使い物にならない:QuickSight 連携で、監査人が自分で検索できる状態を作る。これがないと「システム管理者に問い合わせ」ループになって地獄

SOC2・PCI-DSS などのコンプライアンス対応は、正直 3~6 ヶ月はかかると覚悟した方がいいです。でも一度落ち着くと、自動化で監査対応の負荷が劇的に減ります。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事