Skip to content

CloudTrail 組織トレイル設計書


1. 目的・スコープ

目的

組織トレイル(Organization Trail)を導入し、Organization全体のAPIアクティビティを一元的に記録・集約する。 これにより以下を実現する。

  • 全アカウントの監査ログを漏れなく記録(現在CloudTrailが未設定のctop系・cc-pocを含む)
  • ログの一元集約によるインシデント対応・フォレンジックの迅速化
  • 個別トレイルの重複を解消し、コストを最適化
  • 3省2ガイドライン(医療情報の安全管理ガイドライン)の監査ログ要件への対応

スコープ

  • 組織トレイルの設計・構築(管理イベントのみ。データイベントは対象外)
  • S3バケット(ログ保存先)の設計・構築
  • KMS暗号化キーの設計・構築
  • Delegated Admin登録
  • 個別トレイルの整理方針

データイベントについて: 現状の個別トレイル(cloudtraillog-to-s3等)でもデータイベントは記録していない。CodePipeline用トレイル(S3 WriteOnlyのデータイベント)のみが例外だが、これらは組織トレイルとは別に残す。データイベントの組織トレイルへの追加は今後の検討課題とする(コスト増に注意)。

前提


2. 現状と課題

現状(2026-05-20時点の調査結果)

詳細はセキュリティサービス調査結果を参照。

組織トレイル: 未設定

【グループA: 個別トレイルあり】
  ・fd-aws-production, fd-aws-staging, fd-infra-dev,
    fd-sys, fd-dev, 外部連携, 踏み台, マネジメント
  → cloudtraillog-to-s3(または同等)が各アカウントで稼働中
  → 各アカウントの個別S3バケットにログ保存
  → 組織トレイル作成後に削除可能(重複課金回避)

【グループB: CloudTrailなし ⚠️】
  ・ctop-staging (323155024650)
  ・ctop-production (324454774785) ← 本番環境
  ・cc-poc (499591337329)
  → 監査ログが記録されていない
  → 組織トレイル作成で自動的にカバーされる

【CodePipelineトレイル(削除禁止)】
  ・fd-infra-dev:  codepipeline-source-trail(S3データイベント)
  ・fd-sys:        fd-system-codepipeline-source-cloudtrail(S3データイベント)
  ・fd-dev:        fd-system-codepipeline-source-cloudtrail(S3データイベント)
  → S3データイベントでCodePipelineをトリガーしている
  → 組織トレイルでは管理イベントのみ記録するため代替不可

課題

#課題リスク
1ctop系・cc-pocに監査ログがないセキュリティインシデント時に調査不可
2個別トレイルが各アカウントに分散インシデント時の横断調査が困難
3個別トレイルのログが各アカウントのS3に保存ログの改ざん・削除リスク
4個別トレイルと組織トレイルの重複二重課金

3. アーキテクチャ

全体構成

ログ配信パス

S3オブジェクトパス(CloudTrailのデフォルト。変更不可):
  s3://fd-cloudtrail-organization/AWSLogs/{org-id}/{account-id}/CloudTrail/{region}/YYYY/MM/DD/

  ・org-id: Organization ID(o-l6fkz7kf6p)
  ・account-id: 各メンバーアカウントID
  ・region: イベントが発生したリージョン
  ・YYYY/MM/DD: ログ配信日

  ※ このパス構造はCloudTrailが自動で生成する(カスタマイズ不可)
  ※ Athenaのパーティションはこのパス構造に合わせて設定する(別途設計)

ログ参照方法

インシデント調査時のログ参照手順:
  1. 踏み台アカウント → fd-log-archiveにAssumeRole(read-only-role)
  2. AthenaでS3バケット(fd-cloudtrail-organization)をクエリ
  3. KMS Decrypt権限で暗号化ログを復号(自動)

必要な権限:
  ・fd-log-archiveのS3バケットへのs3:GetObject
  ・fd-log-archiveのKMSキーへのkms:Decrypt
  → fd-log-archiveのread-only-roleに付与済み(role.tf)

直近1年: Athenaで即座にクエリ可能(S3 Standard)
1年〜7年: Glacierから復元後にクエリ(復元: 数分〜12時間)
  → 復元はfd-log-archiveのread-only-roleでS3コンソールまたはCLIから実施
  → 復元後は一時的にStandardにコピーされ、指定日数後に自動削除される
  → 詳細な復元手順は運用手順書で別途整備する

※ Athenaのデータベース・テーブル・パーティション等の詳細設計は別途実施する
  → https://github.com/fastdoctor-jp/mental-online-karte/issues/13019
※ CloudTrailの運用設計・手順の作成は別途実施する
  → https://github.com/fastdoctor-jp/mental-online-karte/issues/13023

新規アカウント追加時の動作

Organizationに新しいアカウントが追加された場合:
  ・組織トレイルが自動的にそのアカウントにも適用される
  ・AWSServiceRoleForCloudTrail(サービスリンクロール)が自動作成される
  ・追加設定は不要

アカウントがOrganizationから削除された場合:
  ・組織トレイルとサービスリンクロールが自動削除される
  ・削除前のログはS3バケットに残る

参考: https://docs.aws.amazon.com/awscloudtrail/latest/userguide/creating-trail-organization.html

4. 組織トレイル設定

トレイル設定

項目設定値理由
トレイル名fd-organization-trail組織全体用であることを明示
組織トレイル有効Organization全アカウントのイベントを記録
マルチリージョン有効全有効リージョンのイベントを記録(ベストプラクティス)
ログファイル検証有効ログの改ざん検知(フォレンジック要件)
管理イベントRead + Write全管理イベントを記録
データイベント無効コスト面から初期は無効。必要に応じて追加検討
Insightsイベント無効初期は無効。GuardDutyで異常検知を担うため、導入後に必要性を再判断
CloudWatch Logs無効ログはS3に保存。リアルタイム異常検知はGuardDutyが担うため不要
SNS通知無効ログ配信ごとの通知は運用上不要。配信エラーはget-trail-statusで確認可能

トレイル作成元

作成元: fd-security-tooling(Delegated Administrator)
理由:
  ・マネジメントアカウントでのTerraform運用を避ける(セキュリティリスク軽減)
  ・SCP管理と同じアカウントで一元管理
  ・Delegated Adminが作成しても、所有者はマネジメントアカウント(AWS仕様)

注意:
  ・Delegated AdminはInsightsの有効化はできない(マネジメントアカウントのみ)
  ・組織トレイルと非組織トレイルの相互変換はマネジメントアカウントのみ

5. S3バケット設計

バケット設定

項目設定値
バケット名fd-cloudtrail-organization
アカウントfd-log-archive (385800115893)
リージョンap-northeast-1
バージョニング有効
パブリックアクセスブロック全て有効
ACL無効(バケット所有者強制)
暗号化SSE-KMS(fd-cloudtrail-key)
S3サーバーアクセスログ有効(ログバケットへのアクセス記録)

ライフサイクルポリシー

目的: 医療情報ガイドラインの監査ログ保持要件に準拠しつつコスト最適化

  0日〜365日:     S3 Standard(Athenaで即座にクエリ可能)
  365日〜2555日:  S3 Glacier Flexible Retrieval(長期保持。復元: 数分〜12時間)
  2555日(7年)経過後: 削除

  ※ Deep Archiveは採用しない。
    理由: コスト差が小さく($0.003/GB/月)、
    監査でログ提示を求められた場合に復元に12〜48時間かかるため。

理由:
  ・Standardを1年にすることで、直近1年のログはAthenaで即座に調査可能
  ・Glacierからの復元も数分〜12時間で完了するため、監査対応時に復元・調査可能
  ・医療情報アクセスログは医師法に基づき7年間保存が必要
    参考: docs/sre/incident-response/audit-requirements-guidelines.md#2-ログ保存管理
  ・CloudTrailログは医療情報へのAPIアクセスも記録するため、7年保持とする

バケットポリシー要件

必要なステートメント:
  1. CloudTrailサービスにGetBucketAclを許可(バケットACL確認用)
  2. CloudTrailサービスにPutObjectを許可(マネジメントアカウントのログ書き込み)
  3. CloudTrailサービスにPutObjectを許可(Organization全体のログ書き込み)

セキュリティ要件:
  ・aws:SourceArn条件でトレイルARNを限定する
  ・s3:x-amz-acl条件でbucket-owner-full-controlを強制する
  ・SourceArnにはマネジメントアカウントIDを使用する
    (Delegated Adminが作成しても、トレイルの所有者はマネジメントアカウント)

参考: AWS公式ドキュメント
  https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-s3-bucket-policy-for-cloudtrail.html

6. KMS暗号化設計

KMSキー設定

項目設定値
キー名(エイリアス)alias/fd-cloudtrail-key
アカウントfd-log-archive (385800115893)
リージョンap-northeast-1
キータイプ対称暗号化(SYMMETRIC_DEFAULT)
キーローテーション有効(自動年次ローテーション)

KMSキーポリシー

必要な権限:
  1. CloudTrailサービスがログ暗号化に使用(GenerateDataKey)
  2. fd-log-archiveの管理者がキー管理
  3. fd-security-toolingの管理者がログ復号(Decrypt)
  4. 必要に応じて他アカウントのSREがログ復号

キーポリシーで許可するプリンシパル:
  ・cloudtrail.amazonaws.com — GenerateDataKey(暗号化)
    ※ EncryptionContext条件(aws:cloudtrail:arn)の設定が必要な場合あり。実装時に確認
  ・fd-log-archive管理者 — 全KMS操作(キー管理)
  ・fd-security-tooling管理者 — Decrypt(ログ参照)
  ・SREロール(踏み台経由) — Decrypt(インシデント調査時)

参考: https://docs.aws.amazon.com/awscloudtrail/latest/userguide/how-kms-works-with-cloudtrail.html

7. Delegated Administrator

登録手順

実施場所: マネジメントアカウント (703480710002)
実施者: SRE

手順:
  1. マネジメントアカウントでCloudTrailコンソールを開く
  2. Settings → Organization delegated administrators → Register administrator
  3. fd-security-tooling (860801568046) を入力して登録

  または、CLI:
  aws cloudtrail register-organization-delegated-admin \
    --member-account-id 860801568046

前提:
  ・CloudTrailのTrusted Accessが有効であること(セクション10の適用手順 Step 1で実施)

Delegated Adminの権限範囲

できること:
  ・組織トレイルの作成・更新・削除
  ・組織トレイルのログ記録の開始・停止
  ・CloudWatch Logsロググループの設定(CLI/API経由のみ)

できないこと:
  ・Insightsの有効化(マネジメントアカウントのみ)
  ・組織トレイル ↔ 非組織トレイルの変換(マネジメントアカウントのみ)
  ・Delegated Adminの追加・削除(マネジメントアカウントのみ)

上限:
  ・1組織あたり最大3つのDelegated Administrator

8. Terraform管理

リソース配置

fd-security-tooling(Terraform):
  ・aws_cloudtrail — 組織トレイル定義

  コードの配置:
    fastdoctor-template/common/security-tooling/cloudtrail.tf

fd-log-archive(Terraform):
  ・aws_s3_bucket — ログ保存用バケット
  ・aws_s3_bucket_policy — CloudTrail配信用ポリシー
  ・aws_s3_bucket_lifecycle_configuration — ライフサイクル
  ・aws_s3_bucket_versioning — バージョニング
  ・aws_s3_bucket_public_access_block — パブリックアクセスブロック
  ・aws_s3_bucket_logging — S3サーバーアクセスログ設定
  ・aws_kms_key — CloudTrailログ暗号化キー
  ・aws_kms_alias — キーエイリアス

  コードの配置:
    fastdoctor-template/common/log-archive/cloudtrail.tf

マネジメントアカウント(手動操作):
  ・Trusted Access有効化
  ・Delegated Admin登録
  → Terraform管理しない(マネジメントアカウントにTerraform環境を置かない方針)

アカウント間の依存関係

fd-security-toolingのaws_cloudtrailリソースで、fd-log-archiveのS3バケットと
KMSキーのARNを指定する必要がある。

fd-security-tooling側(cloudtrail.tf):
  ・s3_bucket_name: fd-log-archiveのバケット名を変数で指定
  ・kms_key_id: fd-log-archiveのKMSキーARNを変数で指定
  → Terraform変数にARN文字列を渡すだけ。特別なクロスアカウント設定は不要

fd-log-archive側(cloudtrail.tf):
  ・S3バケットポリシー: CloudTrailサービスからの書き込みを許可(セクション5で定義)
  ・KMSキーポリシー: CloudTrailサービスからの暗号化を許可(セクション6で定義)
  → これらのポリシーがないとCloudTrailがログを配信できない

適用順序:
  1. fd-log-archiveのS3バケット・KMSキーを先に作成(terraform apply)
  2. fd-security-toolingで組織トレイルを作成(terraform apply)

9. 個別トレイル整理方針

削除対象

組織トレイル安定稼働(1週間)を確認後に削除する。

削除対象(管理イベント記録用の個別トレイル):
  ・fd-aws-production:  cloudtraillog-to-s3
  ・fd-aws-staging:     cloudtraillog-to-s3
  ・fd-infra-dev:       cloudtraillog-to-s3, fd-platform-s3accesslog
  ・fd-sys:             cloudtraillog-to-s3
  ・fd-dev:             cloudtraillog-to-s3, create-aws-resource-900176301532-4cc87778
  ・外部連携:           fd-external-relation-prd-cloudtrail
  ・踏み台:             cloudtraillog-to-s3, fd-common
  ・マネジメント:       cloudtraillog-to-s3

削除方法:
  ・Terraform管理(platform-lite/platformモジュール):
    ⚠️ モジュールごと削除するとS3バケットも消える(force_destroy = true)
    → トレイル(aws_cloudtrail)だけをterraform state rmしてからCLIで削除する
    → または、Terraformコードからトレイルリソースのみ削除してapply
    → S3バケットは既存ログ保持のため残す
    → CodePipelineトレイルは別モジュールなので影響なし
  ・手動作成(マネジメント等): CLI/コンソールで削除
  ・削除前にCloudTrailイベントで組織トレイルのログ配信を確認

削除禁止

CodePipelineトレイル(S3データイベント):
  ・fd-infra-dev:  codepipeline-source-trail
  ・fd-sys:        fd-system-codepipeline-source-cloudtrail
  ・fd-dev:        fd-system-codepipeline-source-cloudtrail

  用途: CI/CDパイプラインの自動起動トリガー(監査ログ目的ではない)
    S3へのアップロード → CloudTrailがデータイベント検知 → EventBridge → CodePipeline起動

理由:
  ・デプロイパイプラインのインフラの一部として動作している
  ・削除するとCI/CDパイプラインが自動起動しなくなる
  ・組織トレイルでは管理イベントのみ記録するため代替不可

個別トレイル削除手順

Terraform管理のトレイル

全て platform/cloudtrail モジュール(aws_cloudtrail + aws_s3_bucket が同一モジュール)。 S3バケットに force_destroy = true が設定されているため、モジュールごと削除すると既存ログが消える。

対象アカウントと Terraform パス:
  ・fd-aws-production:  fastdoctor-template/common/production/globals/cloudtrail/
  ・fd-aws-staging:     fastdoctor-template/common/staging/globals/cloudtrail/
  ・fd-infra-dev:       fastdoctor-template/common/infra-dev/globals/cloudtrail/
  ・fd-sys:             fastdoctor-template/common/amazon-connect/globals/cloudtrail/
  ・fd-dev:             fastdoctor-template/common/develop/globals/cloudtrail/
  ・踏み台:             fastdoctor-template/common/integration/globals/cloudtrail/

アカウントごとの削除手順:
  1. 事前確認
     ・組織トレイルでそのアカウントのログが配信されていることを確認
       aws cloudtrail get-trail-status --name fd-organization-trail --profile {profile}

  2. S3バケットをTerraform管理から外す
     cd fastdoctor-template/common/{env}/globals/cloudtrail/
     terraform state rm 'module.cloudtrail.aws_s3_bucket.cloudtrail-log-bucket'
     terraform state rm 'module.cloudtrail.aws_s3_bucket_policy.cloudtrail-log-bucket'
     terraform state rm 'module.cloudtrail.aws_s3_bucket_lifecycle_configuration.main'

  3. トレイルをTerraformで削除
     ・cloudtrail/main.tf のモジュール呼び出しを削除(またはコメントアウト)
     ・terraform plan で aws_cloudtrail.main の destroy のみ出ることを確認
       (S3バケットは state rm 済みなので plan に出ない)
     ・terraform apply

  4. コメントを残す
     ・削除したコードの位置に旧S3バケット名をコメントで記録
       # 旧個別トレイル削除済み(組織トレイルに移行)
       # 旧ログ保存バケット: fd-cloudtrail-logs-to-s3-{env}(ライフサイクルで自然消滅予定)

fd-infra-dev: fd-platform-s3accesslog

platform/cloudtrailモジュール(aws_cloudtrail.s3accesslog)で管理。
cloudtraillog-to-s3と同じモジュール内にあるため、上記手順で一緒に削除される。

S3バケット(fd-cloudtrail-log-infra)も同様にstate rmで残す。
  terraform state rm 'module.cloudtrail.aws_cloudtrail.s3accesslog'
  ※ s3accesslogリソースがモジュール内に別途ある場合は個別にstate rmが必要

手動作成のトレイル

以下はTerraform管理外のため、CLI/コンソールで削除する。

  ・外部連携: fd-external-relation-prd-cloudtrail
    aws cloudtrail delete-trail --name fd-external-relation-prd-cloudtrail --profile fd-external

  ・踏み台: fd-common
    aws cloudtrail delete-trail --name fd-common --profile common

  ・fd-dev: create-aws-resource-900176301532-4cc87778
    → AWSコンソールで自動生成(Terraform管理外)
    → トレイルのみ削除。S3バケット・CW Logsロググループ・KMSキーは既存ログ参照用に残す
    aws cloudtrail delete-trail --name create-aws-resource-900176301532-4cc87778 --profile fd-dev

  ・マネジメント: cloudtraillog-to-s3
    aws cloudtrail delete-trail --name cloudtraillog-to-s3 --profile {management-profile}

  → S3バケットはそのまま残る(CLIでトレイルを削除してもバケットは消えない)

個別S3バケットの扱い

個別トレイル削除後も、既存のログが保存されているS3バケットは削除しない。

方針:
  ・管理イベントログはサイズが小さい(アカウントあたり月数MB〜数十MB程度)ため、
    永年保管としてそのまま放置する(ライフサイクル追加やGlacier移行は不要)
  ・Terraform管理のバケットはstate rmで管理から外し、コード上にコメントで記録
    (例: # 旧個別トレイルのログ保存バケット: fd-cloudtrail-logs-to-s3-production)
  ・手動作成のバケットはそのまま残る(トレイル削除でバケットは消えない)
  → Terraform管理に再importする必要はない(設定変更の予定がないため)

10. 適用手順

前提作業(マネジメントアカウント)

Step 1: Trusted Access有効化
  aws organizations enable-aws-service-access \
    --service-principal cloudtrail.amazonaws.com

Step 2: Delegated Admin登録
  aws cloudtrail register-organization-delegated-admin \
    --member-account-id 860801568046

構築手順

Step 3: fd-log-archiveにS3バケット・KMSキーを作成
  → fastdoctor-template/common/log-archive/ でterraform apply

Step 4: fd-security-toolingで組織トレイルを作成
  → fastdoctor-template/common/security-tooling/ でterraform apply

Step 5: 動作確認
  ・各アカウントでCloudTrailコンソールを開き、組織トレイルが表示されることを確認
  ・S3バケットにログファイルが配信されていることを確認
  ・KMS暗号化が適用されていることを確認(ファイルのメタデータ)

個別トレイル整理

Step 6: 並行稼働(1週間)
  ・組織トレイルと個別トレイルの両方が稼働する状態で安定性を確認
  ・組織トレイルのログ配信エラーがないことを確認(get-trail-status)

Step 7: 個別トレイル削除
  ・グループAの個別トレイル(cloudtraillog-to-s3等)を削除
  ・CodePipelineトレイルは削除しない
  ・削除後に組織トレイルのみでログが記録されていることを確認

ロールバック手順

組織トレイルに問題が発生した場合:
  1. 組織トレイルの問題を調査(get-trail-status)
  2. 問題が解決できない場合、個別トレイルを再作成(削除済みの場合)
  3. 組織トレイルの修正・再作成

  → 個別トレイル削除前の並行稼働期間中はロールバック不要
    (個別トレイルがまだ稼働しているため)

11. コスト見積もり

組織トレイルのコスト

CloudTrailの料金体系:
  ・管理イベント: 最初のコピー(最初の1トレイル)は無料
  ・2つ目以降のトレイル: $2.00/100,000イベント

組織トレイル導入後:
  ・組織トレイル = 各アカウントにとって1つ目のトレイル(無料)
  ・既存の個別トレイル = 2つ目のトレイル(有料)
  → 個別トレイルを削除することで、重複課金を解消

  ※ 並行稼働期間(1週間)中は組織トレイル + 個別トレイルの2つが
    稼働するため、個別トレイル分が2つ目として課金される。
    並行稼働期間を短く保つことでコストを最小化する。

  ※ CodePipelineトレイルはデータイベントのみ記録しているため
    管理イベントの重複にはならない

S3ストレージコスト:
  ・ログファイルのサイズは環境・操作量に依存
  ・ライフサイクルポリシーでGlacier移行によりコスト最適化

KMSコスト:
  ・KMSキー: $1.00/月
  ・API呼び出し: $0.03/10,000リクエスト

12. セキュリティ考慮事項

ベストプラクティス適合状況

ベストプラクティス対応状況備考
マルチリージョントレイル全有効リージョンのイベントを記録
ログファイル検証改ざん検知
SSE-KMS暗号化専用KMSキーで暗号化
専用S3バケット(別アカウント)fd-log-archiveに集約
S3バージョニング誤削除防止
S3パブリックアクセスブロック全て有効
最小権限のバケットポリシーaws:SourceArn条件付き
ライフサイクル管理7年保持、段階的にGlacier移行
CloudWatch Logs連携無効ログはS3に保存。リアルタイム異常検知はGuardDutyが担うため不要

SCP保護

SCP①(セキュリティサービス保護)で以下を禁止:
  ・cloudtrail:StopLogging — ロギング停止
  ・cloudtrail:DeleteTrail — トレイル削除

→ メンバーアカウントから組織トレイルを削除・停止することはできない
→ マネジメントアカウントはSCP適用外のため操作可能

⚠️ Delegated Admin(fd-security-tooling)もメンバーアカウントのためSCPの制限を受ける。
  Delegated AdminからのCloudTrail操作がブロックされた場合は、
  SCP①にfd-security-toolingを除外するConditionを追加して対応する。

13. 将来検討事項

項目内容時期
データイベント記録S3・Lambda等のデータイベント記録(コスト増に注意)Phase 4以降
Insightsイベント異常なAPI呼び出しパターンの検出。GuardDuty導入後に必要性を再判断Phase 4以降
MFA DeleteS3バケットのMFA削除保護。有効化にルートユーザーのアクセスキーが必要だが、SCP①で作成を禁止しているため現状不可Centralized Root Access導入後に再検討