2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Control Tower のリージョン拒否下で、特定OUだけ Amazon Bedrock(大阪)を無停止で解放する — 検証 → 失敗 → 最終案の記録

2
Last updated at Posted at 2026-08-21

はじめに

私は株式会社GENEROSITYのSREです。約150アカウントをAWS Organizations + Control Towerで運用しています。

先日、あるプロダクトで Amazon Bedrock の Claude Haiku 4.5 を使いたいという依頼を受けたのですが、Control Tower のリージョン拒否(SCP)が正面から立ちはだかり、想像以上に奥行きのある対応になりました。この記事は、そのときの 検証 → 失敗 → 最終案 の記録です。

結論から書きます。

  • リージョン拒否には2種類ある。LZ全体版(AWS-GR_REGION_DENY)は例外を作れず、OU単位で無効化もできない
  • 解は、OU単位版(CT.MULTISERVICE.PV.1)へ切り替え、対象OUだけ ExemptedActionsbedrock:InvokeModel を指定すること。
  • 大阪を管理対象リージョンに追加しないので、コスト増はゼロ
  • 切替は 新しい仕組みを先に全OUへ用意してから、最後に旧版を外す ことで、統制を緩めず無停止で行える。

同じ壁に当たった方の地図になれば幸いです。基本的な設定手順は、私が救われた下記記事が詳しいので、本記事は「やってみて分かったこと」に重心を置きます。

なお、固有のアカウントID・OU ID・SCP ID・プロダクト名は伏せ、構成を一般化しています。

1. 事象:なぜ弾かれるのか

Claude Haiku 4.5 には前提があります。

  • オンデマンドの単一モデル呼び出しができない。必ず推論プロファイル経由で呼ぶ。
  • 国内向けの jp. 推論プロファイルは、内部で 東京(ap-northeast-1)+大阪(ap-northeast-3) にルーティングされる。

私たちの環境は Control Tower のリージョン拒否で 東京とバージニア北部以外を全面拒否していました。したがって推論プロファイルを叩くと、内部で大阪へ流れた瞬間に SCP で弾かれます。

bedrock:InvokeModel ... with an explicit deny in a service control policy

2. 課題:なぜ素直に例外を作れないのか

「対象OUだけ大阪の Bedrock を通す」を素直にやろうとすると、SCP の原則に阻まれます。

  • SCPのDenyはAllowで上書きできない … 別のSCPで「大阪を許可」と足しても、既存のDenyは消えない。
  • CT管理のSCPは手編集できない … 直接書き換えても、LZ更新で元に戻る(ドリフトの原因)。

つまり LZ全体版のリージョン拒否が生きている限り、特定OUだけ穴を開ける方法がない。ここが出発点でした。

守りたかった条件は次の4つです。

  1. リージョン統制は維持する(大阪を全社に開放しない=最小権限)
  2. コスト増を避ける
  3. 既存の稼働アカウントへ影響を出さない
  4. ダウンタイムを出さない

3. 検証 → 失敗 → 最終案

失敗①:専用OUの「SCPだけ」を差し替える

最初の発想は「対象OU用の専用OUを作り、そこに当たっているリージョン拒否SCPを、大阪の Bedrock だけ許可する内容に差し替える」でした。しかし前章のとおり、そのSCPは CT管理で手編集不可、別SCPを足しても Denyは上書き不可この方向は成立しません。

失敗②:専用OUの「コントロールだけ」を無効化する

ならば大元のコントロールをOUから外せないか。list-enabled-controls はOUごとに返り、SCP実体IDもOUで別々。「OU単位で管理されている=OU単位で外せる」と考え、実際に無効化コマンドを叩きました。とはいえ、対象は当時まだアカウントの入っていない空のOUで、しかも結果は次のとおり——AWSに拒否され、状態は何も変わっていません(リージョン拒否はそのまま有効なまま)。

ValidationException: AWS-GR_REGION_DENY control can only be disabled
through the landing zone settings.

LZ全体版のリージョン拒否は、OU単位で無効化できない(ON/OFFのマスタースイッチはLZ側)。見た目の per-OU 表示と、無効化の可否は別物でした。この方向も成立しません。

一時候補(不採用):全社開放

代替として「Control Tower の管理対象リージョンに大阪を追加する(=全OU・全アカウントで大阪を許可)」も検討しました。操作は単純ですが、大阪が全社で開いて最小権限が崩れ、大阪への baseline 展開で コスト増も生じます。条件1・2に反するため、最終的に不採用としました。

最終案:OU単位版へ切り替え、対象OUだけ例外化

行き着いたのが、リージョン拒否そのものを OU単位版(CT.MULTISERVICE.PV.1 に置き換える案です。

  • 全OUに CT.MULTISERVICE.PV.1 を適用(許可=東京+バージニア北部)。
  • Bedrockを使うOUだけ ExemptedActionsbedrock:InvokeModel を追加。
  • LZ全体版のリージョン拒否は無効化する。
  • 大阪は管理対象リージョンに追加しない(baseline展開なし=コスト増ゼロ)。

生成されるSCPは DenyNotAction の形です。ExemptedActions に入れた操作は NotAction(=除外リスト)に載るので、許可外リージョンでもその操作だけは Deny されずに通ります

{
  "Effect": "Deny",
  "NotAction": [
    "iam:*", "kms:*", "aws-marketplace:*", "...(グローバルサービス群)...",
    "bedrock:InvokeModel"        // ← ExemptedActions で追加した1行
  ],
  "Condition": {
    "StringNotEquals": { "aws:RequestedRegion": ["ap-northeast-1", "us-east-1"] },
    "ArnNotLike": { "aws:PrincipalArn": ["arn:aws:iam::*:role/AWSControlTowerExecution"] }
  },
  "Resource": "*"
}

4. 検証Orgでやってみて分かったこと

本番の統制をいきなり触るのは怖いので、本番と同じ構成を再現した使い捨ての検証用 Organizationsで、案を丸ごと通しで実証しました。ここで拾えた知見が、本番の設計をほぼ決めました。

  • OU単位版は成立するCT.MULTISERVICE.PV.1 が有効化でき、AllowedRegions / ExemptedActions / ExemptedPrincipalArns が使える。対象OUに ExemptedActions=bedrock:InvokeModel を指定すると、生成SCPの NotActionbedrock:InvokeModel が入る。
  • 有効化は「新規SCP作成」ではなく「既存SCPのUpdate」:CloudTrail上は UpdatePolicy で、SCPの枚数は増えない。SCPには1OUあたりの枚数・バイト数の上限があるので、これは地味に重要。
  • LZ拒否を外したときのSCPの消え方がOUで違う:専用SCPとして配られているOUはSCPごと削除、他ガードレールと同居しているOUは該当の文だけ削除してSCPは存続。事前に把握できたおかげで、本番で慌てずに済んだ。
  • 大阪の bedrock:InvokeModel がSCPを通過することの確認方法:除外を効かせた状態で大阪のモデルを呼ぶと、SCPのDenyではなく Bedrock側の ValidationException が返る。これは「SCPを通り抜けてBedrockまで到達した」証拠なので、除外が効いていることを決定的に示せる。
  • 疎通jp. の Haiku 4.5 で Converse 実行に成功。モデルアクセスも AVAILABLE。
  • OU移動に伴う再登録は非破壊:1アカウントあたり約3.5分。Configレコーダーの再起動なし・CloudTrail不変・アプリ相当のマーカーも無傷で行えることを実測。

5. 本番:無停止で切り替える

本番は「先に代替(OU単位版)を全OUへ配り切ってから、最後に旧版(LZ全体版)を外す」という順序で実施しました。逆順(先にLZ拒否を消す)にすると、一瞬でも統制が緩む窓ができるためです。常に拒否が二重にかかった状態を保ったまま、主役だけ入れ替えるイメージです。

  1. 全OUに CT.MULTISERVICE.PV.1 を適用(対象OUのみ ExemptedActions=bedrock:InvokeModel)。子OUは継承のため対象外。
  2. 最終確認(全OUで新コントロール有効・対象OUのみ除外・SCP枚数が上限内かを確認し、問題なければ次へ)。
  3. LZ全体版のリージョン拒否を無効化。LZ更新は実測約24分。管理対象リージョンは東京+バージニアのまま(=コスト増ゼロ)、drift は IN_SYNC
  4. 切替確認 → 対象アカウントを除外OUへ移動 → 移動先OUで再登録(各約3.5分・非破壊)。

影響チェック(実機で対比)

  • 除外していないOUの既存アカウント:東京OK / 大阪のEC2拒否 / 大阪のBedrock拒否 / その他拒否(従来どおり)
  • 移動した対象アカウント:東京OK / 大阪のEC2拒否 / 大阪のBedrock通過

「例外は対象OUだけ、それ以外は今までどおり」がきれいに対比で示せました。ダウンタイムゼロ、既存への影響ゼロ、コスト増ゼロで着地です。

なお本番の切替は深夜に実施し、作業開始から動作検証の完了まで約1時間40分(うちLZ更新の待ちが約30分)でした。

6. まとめ:できたこと

当初は「LZ全体版のリージョン拒否を残したまま、特定OUだけ穴を開ける」ことに阻まれました。しかし発想(=どのコントロールを使うか)を変えることで、当初の想定より良い設定に着地できました。

  • リージョン拒否を OU単位版 CT.MULTISERVICE.PV.1 に切り替え、対象OUだけ ExemptedActions=bedrock:InvokeModel で例外化。
  • 統制維持・コスト増ゼロ・無停止で、対象アカウントだけ大阪の Bedrock を解放できた。

余談:この最終案に辿り着けたのは、AIだけの力ではなかった

正直に書くと、失敗①②のあと、私は一度「全社開放しかない」と結論づけ、実際に上司へその案(全社開放)で報告しました。AIと何度も検証を重ね、実際にエラーまで取ったことで、かえって「できない」という確信が強くなっていたのです。

その結論に再検討の余地をくれたのは、報告を受けた上司の「それ、本当にできないの?」という一言と、そこで共有してもらった一次情報(冒頭の記事)でした。AIは与えた前提の中では驚くほど緻密に検証してくれますが、「前提そのものが違うのでは」という問いは、人との対話が連れてきてくれる。AIを使い倒すときこそ、人に相談することの価値を実感した一件でした。

おわりに

リージョン統制を保ちつつ個別の要望に応える、という板挟みは、マルチアカウント運用では避けて通れないテーマだと思います。今回は「対象OUだけ・無停止・コスト増ゼロ」という納得のいく落とし所にたどり着けました。同じ課題に取り組む方の一助になれば幸いです。最後までお読みいただき、ありがとうございました!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?