Skip to content

GuardDuty 組織統合設計書


1. 目的・スコープ

目的

GuardDutyの組織統合を行い、Organization全体の脅威検知を一元管理する。 これにより以下を実現する。

  • ctop-production(本番)を含む未導入アカウントに脅威検知を適用
  • 全アカウントのfindingsをDelegated Adminに集約
  • ルートユーザー利用の検知(MFA設定ができない場合の代替策)
  • 新規アカウント追加時の自動有効化

スコープ

  • GuardDuty組織統合の設計・構築
  • Delegated Admin登録
  • 保護プランの選択
  • Findingsエクスポート設定(S3 + KMS)
  • SCP②のNotActionに guardduty:* を追加(全リージョン有効化のため)
  • 通知設計は別途実施

前提


2. 現状と課題

現状(2026-06-26時点)

GuardDuty導入済み(7アカウント — 個別導入):
  ・production (967691968827)
  ・fd-sys (913831226605)
  ・staging (301608970378)
  ・infra-dev (853790572692)
  ・develop (900176301532) ← SNSサブスクリプション空(通知されていない)
  ・踏み台 (770217130318)
  ・外部連携 (866741171210)

  設定:
    ・Detector有効、finding頻度: 1時間
    ・Runtime Monitoring有効(ECS Fargate Agent Management有効)
    ・EKS Audit Logs無効
    ・Findings: S3にエクスポート + KMS暗号化
    ・通知: EventBridge(severity >= 7)→ SNS → AWS Chatbot → Slack
    ・Terraform管理: platform/guarddutyモジュール

GuardDuty未導入(6アカウント):
  ・ctop-staging (323155024650)
  ・ctop-production (324454774785) ← ⚠️ 本番環境
  ・cc-poc (499591337329)
  ・マネジメント (703480710002)
  ・fd-security-tooling (860801568046)
  ・fd-log-archive (385800115893)

招待ベースの管理関係: なし(確認済み)

課題

#課題リスク
1ctop-production(本番)に脅威検知がない不正アクセスを検知できない
2developのSNSサブスクリプションが空findingsが通知されていない
3個別導入で管理が分散一元的なfindings管理・対応ができない
4新規アカウント追加時に個別導入が必要導入漏れのリスク(実際にctop系・cc-pocで発生)
5許可リージョン(4リージョン)のみ有効化未使用リージョンでの不正行為を検知できない

3. アーキテクチャ

全体構成

組織統合の動作

組織統合を有効化すると:
  ・既存Detector(7アカウント): 自動的にDelegated Adminの配下に入る
  ・未導入アカウント(6アカウント): 自動的にGuardDutyが有効化される
  ・既存findingsは引き継がれる
  ・新規アカウントがOrganizationに追加された場合も自動有効化
  ・Delegated Adminから全アカウントのfindingsを一元管理

4. 組織統合の設定内容

自動有効化設定

項目設定値理由
GuardDuty自動有効化ALL(全メンバー)既存・新規アカウント全てに適用
Finding頻度ONE_HOUR既存設定と同じ

保護プラン

保護プラン設定値理由
S3 Protection有効S3のデータ窃取・破壊検知。Extended Threat Detection連携
EKS Protection(Audit Logs)無効EKSを使用していない
Runtime Monitoring有効メインでECS Fargateを使ってサービスを構築しており、コンテナのランタイム監視が必要
- ECS Fargate Agent Management有効ECS Fargateタスクのプロセス・ネットワーク・ファイル操作をリアルタイム監視
- EC2 Agent Management有効(既存は無効→有効化)踏み台・プロキシ等のEC2を利用しているため有効化する
- EKS Addon Management無効EKSを使用していない
Malware Protection for EC2有効EBSボリュームのマルウェアスキャン
Malware Protection for S3有効(4バケット個別設定)対象バケット選定完了(調査結果参照)。Delegated Adminから設定不可のため各アカウントで個別設定。詳細は「Malware Protection for S3 設計」セクション参照
RDS Protection有効RDSログイン異常検知。本番DBの保護
Lambda Protection有効Lambda通信の脅威検知
Malware Protection for Backup無効一部AWS Backupを使用しているが、現時点では不要。必要になったら検討
Extended Threat Detection有効(デフォルト)マルチステージ攻撃の検知。追加コストなし。自動有効化

マルチリージョン有効化

AWS公式推奨: 全サポートリージョンでGuardDutyを有効化する

理由:
  ・未使用リージョンでの不正アクティビティ(マイニング用EC2起動等)を検知
  ・IAMなどグローバルサービスの検知にも必要
  ・SCPでリソース作成は制限されているが、SCPが適用されないマネジメントアカウントの侵害や
    SCP設定ミスによるリージョン制限の漏れがあった場合の検知層として機能

対応:
  ・SCP②(リージョン制限)のNotActionにguardduty:*を追加
  ・全サポートリージョンでGuardDutyを有効化
  ・Delegated Adminから各リージョンの設定を管理

有効化対象リージョン:
  ・全サポートリージョン(Delegated Adminの自動有効化で対応)
  ・各リージョンでDelegated Admin登録が必要(リージョンごとの操作)

5. Findingsエクスポート

エクスポート設定

GuardDutyのfindings保持期間は90日。長期保存のためS3にエクスポートする。

エクスポート先: fd-log-archive (385800115893)
  ・S3バケット: fd-guardduty-findings(新規作成)
  ・KMS暗号化: 専用キーで暗号化
  ・ライフサイクル: CloudTrailと同じ方針
    Standard(365日) → Glacier(2555日/7年) → 削除

保存期間の根拠:
  ・監査要件ガイドラインではセキュリティログは1年間保存
    参考: docs/sre/incident-response/audit-requirements-guidelines.md
  ・ただしCloudTrail、Config、Security Hub等の監査系サービスのログとの
    相関分析が必要になるケースがあるため、同じ7年保存とする
  ・Findingsのデータ量は少ないためコスト差はほぼなし

S3のFindings分析:
  ・AthenaでFindingsを分析する想定
  ・Athenaのデータベース・テーブル設計、運用設計については今後の検討タスクとする

既存の各アカウントのS3エクスポート:
  ・組織統合後もそのまま動作する(影響なし)
  ・Delegated Adminからの集約エクスポートに移行後、段階的に廃止

6. SCP修正

SCP②のNotActionに guardduty:* を追加

目的: 全リージョンでGuardDutyを有効化するため、リージョン制限から除外する

修正対象: scp_policies/deny_non_approved_regions.json
追加: "guardduty:*"

理由:
  ・AWS公式推奨で全サポートリージョンでの有効化が推奨されている
  ・SCPでリージョン制限されていても、GuardDutyは全リージョンで脅威を検知する必要がある
  ・AWS Control Towerのリージョン制限SCPでもguardduty:*は除外されている
  ・GuardDutyの設定変更はDelegated Adminからのみ可能(SCP①でDeleteDetectorをDeny済み)

7. Terraform管理

リソース配置

fd-security-tooling(Terraform):
  ・aws_guardduty_detector — Delegated Admin用Detector
  ・aws_guardduty_organization_configuration — 組織統合設定
  ・aws_guardduty_publishing_destination — Findingsエクスポート設定(fd-log-archiveのS3を指定)

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

fd-log-archive(Terraform):
  ・aws_s3_bucket — Findingsエクスポート用バケット
  ・aws_s3_bucket_policy — GuardDutyサービスからの書き込み許可
  ・aws_kms_key — Findings暗号化キー

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

マネジメントアカウント(手動操作):
  ・GuardDuty有効化
  ・Delegated Admin登録(各リージョンで実施)
  → Terraform管理しない(マネジメントアカウントにTerraform環境を置かない方針)

既存のTerraformモジュールとの関係

既存: template_modules/common/platform/guardduty/
  ・各アカウントで個別にDetector、S3エクスポート、SNS通知を管理
  ・組織統合後もDetector自体は引き継がれる
  ・通知設定(EventBridge → SNS)は既存のまま動作

組織統合で追加:
  ・fd-security-toolingに組織統合設定を追加
  ・fd-log-archiveに集約エクスポート先を追加
  ・既存モジュールの即時削除は不要(段階的に整理)

8. 適用手順

Step 1: SCP修正(最初に実施)

SCP②のNotActionにguardduty:*を追加
  → fd-security-toolingでterraform apply
  ※ 全リージョンでGuardDutyを有効化するため、先にSCPを修正しておく

Step 2: マネジメントアカウントでGuardDuty有効化 + Delegated Admin登録

コンソール:
  1. GuardDuty コンソールを開く
  2. 「Get Started」→「Enable GuardDuty」
  3. Settings → Delegated Administrator → fd-security-tooling (860801568046) を登録

CLI:
  aws guardduty enable-organization-admin-account \
    --admin-account-id 860801568046 \
    --region ap-northeast-1

  ※ 各リージョンで実施が必要(リージョンごとにDelegated Admin登録)
  ※ マネジメントアカウントでGuardDuty未有効化の場合、
    Delegated Admin登録時に自動有効化される

Step 3〜5: 構築

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

Step 4: fd-security-toolingで組織統合設定を作成
  → fastdoctor-template/common/security-tooling/ でterraform apply
  ・Detector作成
  ・自動有効化設定(ALL)
  ・保護プラン設定
  ・Findingsエクスポート設定(fd-log-archiveのS3を指定)

Step 5: 動作確認
  ・全アカウントでGuardDutyが有効になっていることを確認
  ・未導入だったアカウント(ctop系、cc-poc等)でDetectorが作成されていることを確認
  ・サンプルfindingsを生成して通知が来ることを確認

9. 既存環境への影響

既存Detectorのあるアカウント(7アカウント):
  ・既存Detectorは引き継がれる(再作成されない)
  ・既存のfindingsも引き継がれる
  ・既存の通知設定(EventBridge → SNS → Chatbot → Slack)はそのまま動作
  ・保護プランの設定はDelegated Adminの自動有効化設定に合わせて更新される場合がある
    → 事前に既存設定と組織設定の差異を確認すること

未導入アカウント(6アカウント):
  ・GuardDutyが自動有効化される
  ・有効化直後はfindingsが生成される可能性がある(初回スキャン)

developアカウント:
  ・SNSサブスクリプションが空のため、組織統合とは別に通知設定の修正が必要

10. SCP保護

SCP①(セキュリティサービス保護)で以下を禁止:
  ・guardduty:DeleteDetector — Detector削除
  ・guardduty:DisassociateFromAdministratorAccount — 管理者アカウントからの離脱

→ メンバーアカウントからGuardDutyを無効化・離脱することはできない
→ マネジメントアカウントはSCP適用外のため操作可能

11. コスト

GuardDutyの料金体系:
  ・基本(CloudTrail管理イベント、VPCフローログ、DNSログ): 分析量に応じた従量課金
  ・保護プラン: 各プランごとの従量課金
  ・固定費なし(完全従量課金)

既存コスト実績(2026年5月):
  ・production:  $465/月
  ・fd-sys:      $257/月
  ・staging:     $186/月
  ・infra-dev:   $46/月(4月実績)
  ・develop, 踏み台, 外部連携: 各$20〜50/月(推定)
  ・合計(推定): 約$1,000〜1,100/月

productionのコスト内訳:
  ・Fargate Runtime Monitoring: $220/月(47%)← ECS Fargateタスク数に依存
  ・RDS Login Events:           $67/月(14%)← RDSのvCPU数に依存
  ・CloudTrail管理イベント:      $49/月(10%)
  ・S3 Data Events:              $3/月
  ・Flow Logs / DNS / Lambda:    $1/月
  → Fargate Runtime MonitoringとRDS Login Eventsで6割を占める

コスト方針:
  ・全環境で同じ設定(全保護プラン有効)とする
  ・非本番環境の保護プランを無効にしても節約効果は微小
    (例: infra-devのFargate Runtime Monitoring=$0.01/月、RDS=$4/月)
  ・保護プランのコストはリソース量に比例するため、
    リソースが少ない環境では自然とコストが低くなる
  ・Fargate Runtime Monitoring、RDS Login Eventsはサービス基盤・本番DBの
    脅威検知として必須のため、コスト削減対象としない

既存アカウントへのコスト影響:
  ・組織統合しても既存Detectorはそのまま引き継がれるため、
    既存7アカウントのコストは現状維持(増加しない)
  ・保護プランの設定を変更しない限り、追加コストは発生しない

組織統合による追加コスト:
  ・未導入6アカウント: $20〜100/月(操作量が少ないため)
  ・マルチリージョン有効化: $5〜20/月(未使用リージョンはイベント量がほぼゼロ)
  ・S3エクスポート(fd-log-archive): $1〜2/月(KMSキー$1 + ストレージ微小)
  ・合計追加コスト: 約$30〜120/月(既存コストの3〜10%程度の増加)

12. Malware Protection for S3 設計

詳細な調査経緯・全367バケットの分類結果は S3 バケット棚卸し調査 を参照。

対象バケット

本番環境の全367バケットを棚卸しし、外部ユーザー(患者)が直接 S3 にファイルをアップロードする4バケットを特定した。 Terraform リポジトリ全体で CORS PUT を許可しているバケットが2件のみであること、およびアプリケーションソースコードの presigned URL 生成パターンの調査により、漏れがないことを確認済み。

バケットアカウント内容Terraform管理リージョン日次アップロード月額コスト
fastdoctor-images-productionfd-sys保険証・カルテ画像(Shrine presigned POST)×ap-northeast-1~2,490件~$27.2
mental-reserve-patient-medical-image-productionproductionメンタルヘルス患者の保険証画像(presigned URL PUT)us-east-1~1,203件~$15.4
ai-triage-prd-file-uploadproduction事前問診の症状写真(presigned URL PUT + STS AssumeRole)us-east-1~1,877件~$15.7
online-karte-static-front-productionproduction検査結果・お薬手帳・処方箋PDF(BFF PutObject + presigned PUT)ap-northeast-1~1,123件~$11.2
合計~6,693件/日~$69.5/月

課金形態

  • データスキャン: us-east-1: $0.09/GB、ap-northeast-1: $0.1185/GB。新規アップロードされたオブジェクトのみスキャン
  • リクエスト: us-east-1: $0.000215/件、ap-northeast-1: $0.000282/件
  • 既存オブジェクトはスキャンされない: EventBridge の S3 Object Created イベントがトリガーのため
  • コスト高騰リスク: なし。アップロード頻度は30日間実測済みで安定(日次 ~6,693件)

Terraform 配置

各アカウントで個別設定(Delegated Admin からは設定不可):

production アカウント:
  fastdoctor-template/common/production/globals/s3/guardduty.tf(新規作成)
  → mental-reserve-patient-medical-image-production
  → ai-triage-prd-file-upload
  → online-karte-static-front-production

fd-sys アカウント:
  fastdoctor-template/common/amazon-connect/globals/s3/guardduty.tf(新規作成)
  → fastdoctor-images-production(TF管理外のため import or ARN 直接指定)

新規バケット追加時の漏れ防止策

  1. PR レビューで防ぐ: Claude auto review プロンプト(.github/prompts/claude-auto-review.md)に「S3 バケット新規作成時、外部ユーザーアップロードを受ける場合は GuardDuty + Access Logs 必須」のチェック項目を追加済み
  2. 共通モジュールで強制する: ファイルアップロード用バケットの共通モジュールを作成し、GuardDuty + Access Logs + 暗号化 + パブリックアクセスブロックをバケット作成と同時に自動適用

TBAC(Tag-Based Access Control)設計

参考: AWS 公式 — TBAC の設定

目的

マルウェアスキャンで脅威が検出されたオブジェクトへのアクセスを即時ブロックする。

方式の選定

方式安全性アプリ影響
ホワイトリスト(公式推奨)高(未スキャンもブロック)スキャン完了まで読み取り不可
ブラックリスト(採用)中(検知済みマルウェアをブロック)影響なし

ブラックリスト方式を採用する。 公式推奨はホワイトリスト方式(NO_THREATS_FOUND 以外を全て Deny)だが、アップロード直後〜スキャン完了までの間にアプリからファイルが参照できなくなる影響がある。本システムでは患者がアップロードした保険証・医療画像を医師が即時参照するフローがあるため、アプリ影響を回避するブラックリスト方式を採用する。

ブラックリスト方式のリスクと許容判断:

  • 未スキャン・スキャン失敗のオブジェクトが読み取れる
  • スキャン所要時間の SLA が非公開のため、未スキャン状態の時間幅が読めない
  • ただし GuardDuty が正常稼働している限り、アップロード後短時間でスキャンされるため実質的なリスクは限定的
  • マルウェアが検出された時点で即座にブロックされるため、既知マルウェアの拡散防止としては十分機能する

仕組み

GuardDuty がスキャン完了後に S3 オブジェクトに付与する GuardDutyMalwareScanStatus タグをもとに、バケットポリシーでアクセスを制御する。

タグ値アクセス
NO_THREATS_FOUND許可
THREATS_FOUND拒否
タグなし(未スキャン / スキャン中)許可(ブラックリスト方式)
UNSUPPORTED / ACCESS_DENIED / FAILED許可(ブラックリスト方式)

既存バケットポリシーの現状

バケット既存ポリシーTBAC 適用方法
fastdoctor-images-productionなし新規追加
mental-reserve-patient-medical-image-productionなし新規追加
ai-triage-prd-file-uploadなし新規追加
online-karte-static-front-productionあり(CloudFront OAC 用 Allow)既存ポリシーに TBAC Statement を追加

IAM ロール・アカウント情報

アカウントアカウントIDGuardDuty IAM ロール管理者ロール対象バケット
production967691968827guardduty-malware-protection-s3-role-virginiafd-platform-admin-rolemental-reserve-patient-medical-image-production, ai-triage-prd-file-upload
production967691968827guardduty-malware-protection-s3-role-tokyofd-platform-admin-roleonline-karte-static-front-production
fd-sys913831226605guardduty-malware-protection-s3-role-tokyofd-backend-adminfastdoctor-images-production

※ production はリージョンが異なる(us-east-1 / ap-northeast-1)ため GuardDuty ロールが2つに分かれている

バケットポリシー設計

production / us-east-1 バケット(mental-reserve-patient-medical-image-production, ai-triage-prd-file-upload):

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyReadIfMalware",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::967691968827:assumed-role/fd-platform-admin-role/*",
          "arn:aws:iam::967691968827:role/fd-platform-admin-role"
        ]
      },
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::<BUCKET_NAME>/*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/GuardDutyMalwareScanStatus": "THREATS_FOUND"
        }
      }
    },
    {
      "Sid": "OnlyGuardDutyCanTagScanStatus",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::967691968827:assumed-role/guardduty-malware-protection-s3-role-virginia/GuardDutyMalwareProtection",
          "arn:aws:iam::967691968827:role/guardduty-malware-protection-s3-role-virginia",
          "arn:aws:sts::967691968827:assumed-role/fd-platform-admin-role/*",
          "arn:aws:iam::967691968827:role/fd-platform-admin-role"
        ]
      },
      "Action": "s3:PutObjectTagging",
      "Resource": "arn:aws:s3:::<BUCKET_NAME>/*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "s3:RequestObjectTagKeys": "GuardDutyMalwareScanStatus"
        }
      }
    }
  ]
}

production / ap-northeast-1 バケット(online-karte-static-front-production):

既存の CloudFront OAC Allow Statement に TBAC の Deny Statement 2つを追加する。

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipal",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::online-karte-static-front-production/*",
      "Condition": {
        "StringEquals": {
          "aws:SourceArn": "<CLOUDFRONT_DISTRIBUTION_ARN>"
        }
      }
    },
    {
      "Sid": "DenyReadIfMalware",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::967691968827:assumed-role/fd-platform-admin-role/*",
          "arn:aws:iam::967691968827:role/fd-platform-admin-role"
        ]
      },
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::online-karte-static-front-production/*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/GuardDutyMalwareScanStatus": "THREATS_FOUND"
        }
      }
    },
    {
      "Sid": "OnlyGuardDutyCanTagScanStatus",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::967691968827:assumed-role/guardduty-malware-protection-s3-role-tokyo/GuardDutyMalwareProtection",
          "arn:aws:iam::967691968827:role/guardduty-malware-protection-s3-role-tokyo",
          "arn:aws:sts::967691968827:assumed-role/fd-platform-admin-role/*",
          "arn:aws:iam::967691968827:role/fd-platform-admin-role"
        ]
      },
      "Action": "s3:PutObjectTagging",
      "Resource": "arn:aws:s3:::online-karte-static-front-production/*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "s3:RequestObjectTagKeys": "GuardDutyMalwareScanStatus"
        }
      }
    }
  ]
}

注: S3 ポリシー評価順序として Deny が Allow より優先されるため、CloudFront 経由のアクセスであっても THREATS_FOUND タグのオブジェクトはブロックされる。

fd-sys / ap-northeast-1 バケット(fastdoctor-images-production):

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyReadIfMalware",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::913831226605:assumed-role/fd-backend-admin/*",
          "arn:aws:iam::913831226605:role/fd-backend-admin"
        ]
      },
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion"
      ],
      "Resource": "arn:aws:s3:::fastdoctor-images-production/*",
      "Condition": {
        "StringEquals": {
          "s3:ExistingObjectTag/GuardDutyMalwareScanStatus": "THREATS_FOUND"
        }
      }
    },
    {
      "Sid": "OnlyGuardDutyCanTagScanStatus",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:sts::913831226605:assumed-role/guardduty-malware-protection-s3-role-tokyo/GuardDutyMalwareProtection",
          "arn:aws:iam::913831226605:role/guardduty-malware-protection-s3-role-tokyo",
          "arn:aws:sts::913831226605:assumed-role/fd-backend-admin/*",
          "arn:aws:iam::913831226605:role/fd-backend-admin"
        ]
      },
      "Action": "s3:PutObjectTagging",
      "Resource": "arn:aws:s3:::fastdoctor-images-production/*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "s3:RequestObjectTagKeys": "GuardDutyMalwareScanStatus"
        }
      }
    }
  ]
}

既存オブジェクトへの影響

ブラックリスト方式のため、既存オブジェクト(タグなし)への影響はなしTHREATS_FOUND タグが付いたオブジェクトのみ Deny されるため、タグなしオブジェクトは通常通りアクセス可能。

アプリ側の影響

ブラックリスト方式のため、アプリ側への影響はなし

状態アクセス備考
アップロード直後(タグなし)許可スキャン完了を待たずに参照可能
スキャン完了(NO_THREATS_FOUND許可
マルウェア検知(THREATS_FOUND拒否即時ブロック
スキャン失敗(FAILED 等)許可リスク許容(GuardDuty 正常稼働前提)

検出範囲の制約

サポート・SA 確認済みの内容:

  • GuardDuty のスキャンエンジンはファイルベースの静的検出(ライブ挙動解析なし)
  • AWS 内製エンジン + Bitdefender のシグネチャベース + ヒューリスティック + ML 検出
  • 特定 CVE をトリガーする構造かどうかを判定する仕組みではない
  • libpng/libjpeg 脆弱性を突く細工画像の検出は保証されない
  • 既知の悪性コード・シグネチャに合致するペイロードが含まれていれば検出される可能性はある
  • ライブラリ自体の脆弱性管理は Inspector の領域

参考: GuardDuty マルウェア検出スキャンエンジン

隔離バケット

マルウェア検知されたオブジェクトの調査・証跡保持のため、隔離用バケットを用意する。

アカウント隔離バケット名リージョン備考
productionfd-malware-quarantine-productionap-northeast-1us-east-1 バケットからのコピーはクロスリージョン転送(データ転送料発生)
fd-sysfd-malware-quarantine-fd-sysap-northeast-1

設定:

  • パブリックアクセスブロック: 全て有効
  • 暗号化: SSE-S3(デフォルト)
  • バージョニング: 有効
  • ライフサイクルポリシー: 90日後に Glacier 移行、365日後に削除(監査要件ガイドラインに準拠)
  • アクセス: 管理者ロール(fd-platform-admin-role / fd-backend-admin)のみ

手動隔離手順:

bash
# 1. 管理者ロールで感染オブジェクトを隔離バケットにコピー
aws s3 cp \
  s3://<SOURCE_BUCKET>/<OBJECT_KEY> \
  s3://fd-malware-quarantine-production/<SOURCE_BUCKET>/<OBJECT_KEY> \
  --profile <ADMIN_PROFILE>

# 2. 元バケットから削除
aws s3 rm s3://<SOURCE_BUCKET>/<OBJECT_KEY> --profile <ADMIN_PROFILE>

Terraform 配置:

production アカウント:
  fastdoctor-template/common/production/globals/s3/malware-quarantine.tf(新規作成)

fd-sys アカウント:
  fastdoctor-template/common/amazon-connect/globals/s3/malware-quarantine.tf(新規作成)

Lambda 自動隔離(将来オプション)

初期リリースでは TBAC + 手動対応で運用する。運用後に手動対応の頻度が高い場合、EventBridge → Lambda による自動隔離を検討する。

項目内容
トリガーEventBridge: GuardDuty Malware Protection Object Scan ResultTHREATS_FOUND
処理感染オブジェクトを隔離バケットにコピー → 元バケットから削除
隔離バケットライフサイクルポリシー(90日→Glacier、365日→削除)を設定
考慮事項医療記録は「原則削除しない」設計方針との整合性を確認する必要がある

Terraform 配置

production アカウント:
  fastdoctor-template/common/production/globals/s3/guardduty-tbac.tf(新規作成)
  → mental-reserve-patient-medical-image-production: aws_s3_bucket_policy(新規)
  → ai-triage-prd-file-upload: aws_s3_bucket_policy(新規)
  → online-karte-static-front-production: 既存 aws_s3_bucket_policy に Statement 追加

fd-sys アカウント:
  fastdoctor-template/common/amazon-connect/globals/s3/guardduty-tbac.tf(新規作成)
  → fastdoctor-images-production: aws_s3_bucket_policy(新規)

適用手順

Step 1: infra-dev でポリシー検証
  ・テスト用バケット(connect-test-xxx)に TBAC ポリシーを適用
  ・EICAR ファイルアップロード → THREATS_FOUND タグ付与 → GetObject が Deny されることを確認
  ・正常ファイルアップロード → NO_THREATS_FOUND タグ付与 → GetObject が許可されることを確認
  ・タグなしオブジェクト → GetObject が許可されることを確認(ブラックリスト方式)
  ・GuardDuty 以外からのタグ変更が Deny されることを確認

Step 2: staging でアプリ動作確認
  ・対象: mental-reserve-patient-medical-image-staging
    (staging 環境で確認可能な唯一の対象バケット)
  ・TBAC ポリシーを適用し、既存のアプリワークフローが正常に動作することを確認
    - 患者の保険証アップロード → 医師の画像参照が正常に動作するか
    - presigned URL 経由のアクセスが正常か
  ・問題があれば即時ポリシーを削除してロールバック

Step 3: 本番適用
  ・4バケットに TBAC ポリシーを適用
  ・適用後、正常なファイルのアップロード・参照が動作していることを監視
  ・Slack 通知で THREATS_FOUND の検知を監視

SCP によるタグ改ざん防止

参考: AWS Organizations — タグの変更を承認済みプリンシパルに制限する

バケットポリシーの OnlyGuardDutyCanTagScanStatus で IAM ロール以外のタグ変更を防止しているが、Organizations SCP で追加の防御層を設ける。

SCP ポリシー

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyGuardDutyTagModification",
      "Effect": "Deny",
      "Action": [
        "s3:PutObjectTagging",
        "s3:DeleteObjectTagging"
      ],
      "Resource": "*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "aws:TagKeys": "GuardDutyMalwareScanStatus"
        },
        "ArnNotLike": {
          "aws:PrincipalArn": [
            "arn:aws:iam::967691968827:role/guardduty-malware-protection-s3-role-virginia",
            "arn:aws:iam::967691968827:role/guardduty-malware-protection-s3-role-tokyo",
            "arn:aws:iam::967691968827:role/fd-platform-admin-role",
            "arn:aws:iam::913831226605:role/guardduty-malware-protection-s3-role-tokyo",
            "arn:aws:iam::913831226605:role/fd-backend-admin"
          ]
        }
      }
    }
  ]
}

適用対象

OU適用理由
Workloads OU適用production, fd-sys が所属
Security OU適用不要対象バケットなし
Sandbox OU適用infra-dev での TBAC 検証用

Terraform 配置

fastdoctor-template/common/security-tooling/scp.tf に追加
または scp_policies/ ディレクトリに新規ポリシー JSON を追加

13. 検知時の対応フロー

マルウェア検知時のフロー

1. GuardDuty がスキャン完了
   → THREATS_FOUND タグを付与
   → TBAC により即時アクセスブロック

2. 通知
   → GuardDuty Finding: Object:S3/MaliciousFile(Severity: HIGH)
   → 既存パイプライン: EventBridge → SNS → AWS Chatbot → Slack (#squad-sre-noti-security)

3. SRE が確認
   → Finding の S3ObjectDetails から対象オブジェクトを特定
   → 脅威の種類・深刻度を確認
   → CloudTrail(データイベント有効化済みの場合)でアップロード元を特定
   → アプリ側チームに連絡(対象バケットのオーナーチーム)

4. 対応判断
   → 管理者ロールで感染オブジェクトを隔離バケットにコピー
     (DenyReadIfMalware から管理者ロールは除外済みのためアクセス可能)
   → 元バケットから削除
   → 誤検知の場合: タグを NO_THREATS_FOUND に手動更新(管理者ロールで実施)

5. ユーザー対応
   → アップロード元のユーザー(患者)に連絡
   → 端末のセキュリティスキャンを依頼
   → 必要に応じてファイルの再アップロードを案内

誤検知時の対応

GuardDuty の誤検知が確認された場合:
  1. SCP 除外ロール(管理者)でタグを手動更新
     aws s3api put-object-tagging \
       --bucket <BUCKET_NAME> \
       --key <OBJECT_KEY> \
       --tagging '{"TagSet":[{"Key":"GuardDutyMalwareScanStatus","Value":"NO_THREATS_FOUND"}]}'

  2. GuardDuty でサプレッションルールを追加(同一パターンの誤検知防止)

14. Macie の方針

Macie は現時点では見送り、ガバナンス整備後に Phase 4 として導入予定。 詳細は OU・アカウント設計書の Macie 方針セクション を参照。


15. 今後のタスク

#タスク概要
1通知設計Delegated Adminへの通知集約、Datadog統合、Slack通知先の整理
2developのSNSサブスクリプション修正現在通知されていない問題の修正
3既存S3エクスポートの整理fd-log-archive集約後に各アカウントの個別エクスポートを段階的に廃止
4サプレッションルール運用しながら誤検知を抑制するルールを追加
5Security Hub統合Security Hub導入時にGuardDutyのfindingsを自動集約
6Malware Protection for S3の設計✅ 完了(2026-08-14)。調査結果 / 対象4バケット確定 / コスト試算済み → 実装へ
7Athena分析基盤の設計Findingsエクスポート先S3のAthenaテーブル設計・運用設計(CloudTrailのAthena設計と合わせて実施)
8Malware Protection for S3の実装4バケットへの aws_guardduty_malware_protection_plan 適用。各アカウントで個別設定
9S3 Server Access Logs の有効化医療・個人情報バケットに監査ログ設定。TF管理バケットはコードで、管理外は手動 or import
10ファイルアップロード用バケット共通モジュールGuardDuty + Access Logs + 暗号化を自動適用する共通モジュール。新規バケット追加時の漏れ防止
11TBAC バケットポリシーの実装infra-dev 検証 → staging 動作確認(mental-reserve-patient-medical-image-staging)→ 本番4バケットに適用
12SCP タグ改ざん防止の実装Workloads OU に GuardDutyMalwareScanStatus タグ変更制限 SCP を適用
13EICAR 画像埋め込み検出テストGuardDuty の画像ファイル内ペイロード検出力を検証。テスト計画(doc 未作成: tasks/guardduty-s3-malware-eicar-image-test.md
14検知時対応フローの文書化・周知マルウェア検知時の Slack 通知 → 担当者判断 → ユーザー連絡の運用フローをチームに周知
15隔離バケットの作成production / fd-sys に fd-malware-quarantine-* バケットを作成。Terraform で管理