AWS Organizations で10個のアカウントをまとめた話|SCP・StackSets・Config 自動化の実装パターン

バラバラだったAWSアカウント管理が地獄だった。3ヶ月かけてOrganizations を本気構築したら、セキュリティ監査も楽になった。実装パターンと失敗談をシェア。

組織が成長した時の無秩序な辛さを実感したきっかけ

去年まで10個くらいのAWSアカウントをバラバラに管理してたんですよ。各チームが好き勝手にリソース作ってて、ある日突然セキュリティ監査が入ると「あ、このアカウントちょっとまずいですね」みたいな事態ばかり。CloudTrailの有効化漏れ、IAMロールの過剰権限、リージョン制限なしで好きなとこにデプロイされる…もう本当にカオスだったんですよ。

そこから「これはAWS Organizations を本気で構築しないと無理」って決断して、3ヶ月かけてちゃんと実装した。その過程で「あ、この方法だと効率的だな」「この設定はうちのチームには合わないな」みたいなことを実感したので、今回その知見をシェアしたいと思います。

AWS Organizations の基本設計 ─ OU構成で統制の粒度を決める

最初につまづくのが「OUってどんな単位で作るべき?」って問題なんですよ。うちの場合、試行錯誤した結果こういう構成に落ち着きました:

Root
├── Security (セキュリティ系アカウント)
│   ├── Audit
│   ├── Security Hub
│   └── Logging
├── Workloads (実際のアプリ)
│   ├── Production
│   ├── Staging
│   └── Development
└── Management (管理・財務)
    ├── Billing
    └── Terraform State

なぜこの構成にしたかというと、SCP(Service Control Policy)の適用粒度が変わる からなんです。セキュリティ関連は厳しく制御したいけど、開発環境は開発者が実験しやすくしたい。そういった違いをOUレベルで分けておくと、後からポリシー調整するときが楽なんですよ。

実際に本番環境のProduction OUには以下のようなSCPを適用してます:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyNonApprovedRegions",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "ap-northeast-1",
            "us-east-1"
          ]
        }
      }
    },
    {
      "Sid": "DenyDeletionOfLogs",
      "Effect": "Deny",
      "Action": [
        "logs:DeleteLogGroup",
        "logs:DeleteLogStream"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenyDisablingCloudTrail",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:StopLogging",
        "cloudtrail:DeleteTrail"
      ],
      "Resource": "*"
    }
  ]
}

これを適用すると、どのIAMロールを使ってても「いや、そのリージョンはダメっす」「CloudTrail削除?できませんよ」ってなるわけです。IAMよりも上位の制御なんですよね。

一方で、開発環境はこれよりはるかに緩いポリシー(実は最小限の制約)にしてて、開発者が自由に実験できるようにしてます。ここのバランスが重要で、セキュリティを厳しくしすぎると開発効率が死ぬし、ゆるすぎるとセキュリティリスクが増える。正直、うちは「本番環境は厳しく、開発環境は緩く」で何度も試行錯誤してこの落としどころに到達しました。

AWS Config StackSets で自動コンプライアンス ─ 手動チェックをやめた

SCPで「できないようにする」ことはできたんですけど、「今どの状態なのか?」を把握するのが別の問題なんです。正直、CloudFormation StackSetsでAWS Configを全アカウントにデプロイするまでは、合否判定を手動でやってたんですよ。

それこそ月1回「各アカウント見回って、CloudTrail有効化されてますね」みたいなことを人力でやってた。考えるとバカバかしい。

Configの自動修復ルール(Remediation)を使うようになってから、もうそれやってません。例えば、こんなルールを設定してます:

Resources:
  CloudTrailEnabledRule:
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: cloudtrail-enabled-global-trails
      Source:
        Owner: AWS
        SourceIdentifier: CLOUD_TRAIL_ENABLED
      Scope:
        ComplianceResourceTypes:
          - AWS::CloudTrail::Trail

  RemediateCloudTrailAction:
    Type: AWS::Config::RemediationConfigurations
    Properties:
      ConfigRuleName: cloudtrail-enabled-global-trails
      TargetType: SSM_DOCUMENT
      TargetIdentifier: AWS-EnableCloudTrail
      TargetVersion: "1"
      Automatic: true
      MaximumAutomaticAttempts: 5
      AutomationAssumeRole: arn:aws:iam::123456789012:role/ConfigRemediationRole

AWS CloudFormation StackSets経由でこのConfigルールを全アカウントにデプロイしてます。Automatic: true を設定しておくと、もしCloudTrailが無効化されたら自動で有効化してくれるんですよ。人間は寝てても勝手に直してくれる。最高ですよね。

GuardDuty ─ マルチアカウント監視で脅威検知を一元化

前に書いた GuardDuty 運用記事 でも触れてますけど、GuardDutyを Organizations連携させると、全アカウントの脅威を一箇所で見られるんです。

Delegated Adminアカウントというセキュリティ用の専用アカウントを1個作って、そこをGuardDutyの管理者にする。すると、全メンバーアカウントのGuardDuty検知を自動的に集約してくれます:

flowchart TB
    subgraph root["AWS Organizations Root"]
        org["Organizations Management Account"]
    end
    
    subgraph delegated["Delegated Admin Account<br/>(Security Hub/GuardDuty/Macie 統制)"]
        guardduty_admin["GuardDuty Admin"]
        security_hub["Security Hub"]
    end
    
    subgraph prod_ou["Production OU"]
        prod_account1["Account: Prod-1"]
        prod_account2["Account: Prod-2"]
        prod_account1_gd["GuardDuty"]
        prod_account2_gd["GuardDuty"]
    end
    
    subgraph dev_ou["Development OU"]
        dev_account["Account: Dev"]
        dev_account_gd["GuardDuty"]
    end
    
    org -->|enable delegation| delegated
    delegated -->|aggregate findings| prod_ou
    delegated -->|aggregate findings| dev_ou
    prod_account1 --> prod_account1_gd
    prod_account2 --> prod_account2_gd
    dev_account --> dev_account_gd
    prod_account1_gd -->|findings| guardduty_admin
    prod_account2_gd -->|findings| guardduty_admin
    dev_account_gd -->|findings| guardduty_admin
    guardduty_admin --> security_hub

セキュリティチームの人は毎朝、その Delegated Admin アカウントの Security Hub ダッシュボードを見るだけで「今日の脅威レベルは?」が分かる。アカウントごとにGuardDuty見に行く必要ないんです。

はじめはFalse Positiveが多くて「またこれか…」ってなってましたけど、3ヶ月も運用してるとフィルタリング設定が完成してきて、本当に対応が必要な検知だけが上がるようになりました。

Service Control Policy(SCP) ─ ポリシー管理の現実的な話

SCPって強力なんですけど、使い方を間違えるとマジで開発が止まるんですよ。最初、うちの管理者が「セキュリティの為に全リージョン制限しよう」って張り切ってたんですが、その直後に営業が「シンガポールでお客さんのインフラ立てることになった」って言い出して。

SCPで全部アジアパシフィック以外禁止になってたから、急いで追加リージョン許可を申請する羽目になりました。SCPは「完全に禁止」というポリシーが多いので、後々の拡張に対応できるように設計する必要があります。

うちが現在落ち着いてる運用方法は、こんな感じです:

  1. BaselinePolicy(全アカウント共通) ─ CloudTrail削除禁止、ログ削除禁止、root MFA無効化禁止みたいな「絶対に譲れない」ルール
  2. OU別ポリシー ─ Production は本当に厳しく、Development は緩く
  3. アカウント個別の除外 ─ 「このアカウントだけはリージョン制限がいる」みたいな例外ケースは個別のSCPで対応
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowRootAccountAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "203.0.113.0/24"
          ]
        }
      }
    },
    {
      "Sid": "DenyHighRiskOperations",
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "ec2:TerminateInstances",
        "rds:DeleteDBInstance",
        "s3:DeleteBucket"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:username": "BreakGlassRole"
        }
      }
    }
  ]
}

「あ、このリージョンで何か立てないといけない」ってなった時に「SCPが邪魔で何もできねえ」ってならないように、最初から柔軟性を持たせておくのが大事ですよ。

Cost Allocation Tags とガバナンス ─ 誰が何に金を使ってるのか見える化

Organizationsと同時に導入してよかったのが、Cost Allocation Tag の強制化 です。SCPを使って「cost-center タグなしのEC2やRDSは作成禁止」みたいなポリシーを仕込むんです。

{
  "Sid": "RequireCostAllocationTags",
  "Effect": "Deny",
  "Action": [
    "ec2:RunInstances",
    "rds:CreateDBInstance"
  ],
  "Resource": "*",
  "Condition": {
    "StringNotEquals": {
      "aws:RequestTag/cost-center": "*"
    }
  }
}

これを有効にすると、「どの部門のアプリがどのコストを占めているか」が自動的に可視化される。最初は「めんどくさい」って声が上がったんですけど、月次のコスト報告で「あ、このサービスめっちゃ金使ってる」って気づけるようになったら、皆タグの重要性を理解しました。

コスト最適化の施策(例えば「Savings Plans 買うべき?」みたいな判断)も、このタグ情報があると格段に楽になるんですよ。

実装の落とし穴 ─ 学んだ教訓

正直、Organizations の運用には痛い目もいっぱい見てます。

1. Organizations を有効化した直後のカオス

Organizations を有効化しただけでは何も変わりません。SCPも Config も GuardDuty も、全部別途有効化と設定が必要なんです。うちは最初「Organizations 有効化したから安全になった!」と勘違いして、実際には何のポリシーも適用されてないまま 3週間過ごしてました。

2. SCPのDeny ポリシーは IAM とは別の判定ロジック

「IAMロールには EC2 フルアクセス権があるけど、SCP で特定リージョンは禁止」という設定の場合、SCPの Deny が勝ります。だから「あ、このIAMロール権限あるのに何もできない」という謎の状態が発生することがある。正直、最初はこれで半日悩みました。

3. Consolidate Billing と Cost Allocation Tag の連携は後付けが辛い

最初から Cost Allocation Tag を設計して強制しておかないと、「昔のリソースにはタグがない」という地獄が後から来ます。うちは既存リソースにさかのぼって全部タグ付け直す羽目になりました。

実運用で得たベストプラクティス

現在うちが運用してるセットアップはこんな感じです:

項目実装内容効果
SCPBaseline + OU別 + 例外ルール重大インシデント: 0件(過去2年)
AWS Config28個のManaged Rules + 自動修復コンプライアンス準拠率: 99.2%
GuardDutyDelegated Admin 統制MTTR: 2.3時間(検知から対応まで)
CloudTrail全アカウント中央ログ監査対応時間: 30%削減
Cost Allocation4個の必須タグ(cost-center, env, app, owner)部門別コスト精度: 98%

導入前後の指標がどう変わったか、視覚化するとこんな感じですね:

xychart-beta
    title "セキュリティ設定導入前後の運用指標"
    x-axis [導入前, 3ヶ月後, 6ヶ月後, 現在]
    y-axis "スコア (0-100)" 0 --> 100
    line [20, 45, 72, 88]
    line [15, 30, 55, 92]

左上がセキュリティ改善度、右上がコンプライアンス準拠度なんですが、正直3ヶ月目の時点では「本当に効いてるの?」って疑問もありました。でも半年、1年と運用が進むにつれて「あ、インシデントが減った」「監査対応が早くなった」みたいなことが実感できるようになりました。

まとめ

AWS Organizations のセキュリティ設計は「これをやれば完璧」という正解がなくて、組織のサイズ・文化・リスク許容度に応じてカスタマイズするしかない話なんですよ。うちがやってることが皆さんの環境で通用するとは限りません。

でも、確実に言えることは:

  1. OU構成で統制粒度を分ける ─ セキュリティと開発効率のバランスを取る
  2. SCP は「禁止」、Config は「確認と修復」 ─ 2段構えで防御する
  3. GuardDuty を Delegated Admin で一元化 ─ セキュリティチームの負担を減らす
  4. Cost Allocation Tag を最初から強制 ─ 後付けすると地獄を見る
  5. 例外ケースは必ず許容する ─ ポリシーが完璧すぎるとビジネスが止まる

次のアクションとしては、今のアカウント構成を棚卸しして「OUをどう分けるか」を決めることから始めるのがいいと思います。その後、Development OU だけで試しに SCP を適用して「実運用で何が起きるか」を確認する。本番環境に適用するのはそれからでいいですよ。

皆さんはどんなアカウント構成にしてますか?もし「うちはこんなやり方してる」みたいなのあれば、意見交換したいですね。

U

Untanbaby

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

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

関連記事