0
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?

SCP の抜け漏れをどう防ぐか ― 公式サンプルの 6 観点で学び直した話

0
Posted at

マルチアカウント環境の整備に合わせて、SCP (サービスコントロールポリシー) を自己流で作成しました。
組織からの離脱や CloudTrail の停止など、「されては困ること」を Deny する構成で、それなりに守れているつもりでいました。

その後 AWS 公式サンプル を発見して読み直したところ、自分の SCP に抜けが複数あることに気付きました。
自己流では観点が抜け漏れやすいという反省と、公式サンプルという "標準ライブラリ" の参照を推奨する意味を込めて書き残しておきます。

本記事は、IAM Identity Center と AWS Organizations を整理していくシリーズの一つです。

1. SCP とは?

SCP (Service Control Policy) は、AWS Organizations で利用できるポリシーの一つです。
IAM ユーザーやロールに対するアクセス許可を一元的に制御する「ガードレール」として機能します。

Organizations のポリシーには、SCP のほかに RCP (リソースコントロールポリシー) や Tag Policy などがあります。
そのなかで SCP は、アクセス許可の上限を定めるガードレール として基本的な役割を担います。

Allow list と Deny list

SCP の運用方針には、大きく 2 つのアプローチがあります。

  • Allow list 方式: FullAWSAccess を外し、許可する操作だけを明示的に列挙する
  • Deny list 方式: FullAWSAccess を残したまま、禁止したい操作を Deny で追加する

Allow list は厳密ですが、許可する操作を全て記載する必要があるため、運用負荷は高くなります。
Deny list は既存の FullAWSAccess をベースに「これだけはやらせない」を追加していく形で、今回はこちらで進めます。

ポリシー数とサイズの制限

SCP には見落としがちな制限があります。

  • 1 エンティティ (Root / OU / Account) にアタッチできる SCP は 最大 5 件 (AWS 管理の FullAWSAccess も 1 枠を使う)
  • 1 つの SCP のサイズは 5,120 文字 まで

この制限は、後の章でポリシーを統合するかどうかの判断材料にもなります。

2. 自己流で考えていた SCP

マルチアカウント環境の整備に合わせて、組織全体と Workloads OU の 2 レベルで SCP を書きました。
そして「停止・削除」系の操作を防ぎました。

  • 組織からの離脱 (organizations:LeaveOrganization)
  • CloudTrail, GuardDuty, AWS Config の無効化 (DeleteTrail, DeleteDetector, StopConfigurationRecorder など)
  • IAM Identity Center アカウントインスタンスの作成 (sso:CreateInstance)
  • IAM ユーザーの作成 (iam:CreateUser / iam:CreateAccessKey)

IAM Identity Center のインスタンスについてはこちらを参照ください。

「されては困ること」を列挙して Deny したので、これで守れているつもりでいました。
しかし実際は、これではまだまだ守れないのでした。

停止・削除を塞いでも、設定変更で実質無効化できる

公式ドキュメントと AWS 公式サンプル を読み直したところ、自分の SCP には 設定変更系の抜け道 が複数残っていることに気が付きました。
以下のように回避すると、「されては困ること」を実現できてしまいます。

CloudTrail

  • UpdateTrail で対象リージョンを絞り込む、S3 バケットを差し替える → ログが実質止まる
  • PutEventSelectors で Management / Data イベントを空にする → 証跡が記録されない

GuardDuty

  • UpdateDetector で Enable: false にする → 削除せずに検出を停止できる

Config

  • DeleteDeliveryChannel で配信先を消す → 記録は動いても外部に出ない

IAM ユーザー禁止 (IAM Identity Center でのログインに寄せるケース)

  • CreateLoginProfile で既存 IAM ユーザーにパスワードを付与する → コンソールでログイン可能になる

「停止・削除を塞いだだけ」では守れていません。
自分の SCP を "ガードレール" と呼んでいいのか、怪しくなってきました。

3. 公式サンプルの 6 カテゴリで点検する

抜けに気付いた後、aws-samples/service-control-policy-examples を真面目に読み直しました。

このリポジトリは 8 カテゴリで SCP のサンプルを整理しており、冒頭には "Recommended Starting Points" として 6 つの基礎 SCP が示されています。

  1. メンバーアカウントの離脱防止
  2. 承認済みリージョンの強制
  3. ルート認証情報のブロック
  4. ルートユーザーのアクション制限
  5. セキュリティサービスの無効化防止
  6. 機微な S3 バケットの保護

自分の SCP をカテゴリで見直してみると、実装済みはカテゴリ 1 と 5 の一部だけでした。
6 カテゴリ中 2 つ しか埋まっていなかったのです。

そこで、抜けを埋めた強化版に加え、リージョン強制 (カテゴリ 2) とルート認証情報ブロック (カテゴリ 3) を追加で実装することにしました。

実装と見送りの整理

最終的な実装状況と判断理由をまとめます。

# カテゴリ 実装状況 理由
1 メンバーアカウントの離脱防止 実装 Sid DenyLeaveOrganization
2 承認済みリージョンの強制 実装 ap-northeast-1 単一運用を明示的に強制
3 ルート認証情報のブロック 実装 ルートは一元管理済みだが保険として追加
4 ルートユーザーのアクション制限 不要 カテゴリ 3 で一括 Deny するため重複
5 セキュリティサービスの無効化防止 実装 (強化版) 次章で詳細
6 機微な S3 バケットの保護 不要 現時点で該当するバケットなし

6 カテゴリを全部入れる必要はなく、環境に応じて「なぜ入れる / 入れないか」を言語化できる状態が大事だと感じました。

4. SCP を 1 本に統合した設計

実装にあたって悩んだのが、新しく追加する SCP を 別ファイルに分けるか、既存に束ねるか でした。

1 本に統合する判断

結論として、Root に「組織全体のガードレール」を 1 本 (OrganizationGuardrailsSCP) に集約し、Workloads OU 固有のものは別 SCP (WorkloadsSCP) に分ける構成にしました。

  • SCP は 1 エンティティあたり 5 件までの制限があり、分けすぎると枠を圧迫する
  • 「組織全体のガードレール」という 1 コンセプトで整理でき、コンソール上の見通しも良くなる
  • Sid で目的を区切れば可読性は保てる

SCP 一覧を見ると、FullAWSAccess (AWS 管理ポリシー) に加えて、OrganizationGuardrailsSCP と WorkloadsSCP の 2 本が並んでいます。

OrganizationGuardrailsSCP (Root)

Root にアタッチする統合版の SCP です。

公式サンプルからの差分

自分の環境に合わせて変えた部分を抜粋します。JSON 全文は 公式サンプル を参照してください。

CloudTrail / GuardDuty / Config に設定変更系を追加

{
  "Sid": "DenyDisableCloudTrail",
  "Effect": "Deny",
  "Action": [
    "cloudtrail:StopLogging",
    "cloudtrail:DeleteTrail",
    "cloudtrail:UpdateTrail",
    "cloudtrail:PutEventSelectors"
  ],
  "Resource": "*"
}

同様に GuardDuty には UpdateDetector / DisassociateFromMasterAccount / StopMonitoringMembers / DeleteMembers を、
Config には DeleteDeliveryChannel / PutConfigurationRecorder / PutDeliveryChannel を追加しています。

Region: ap-northeast-1 のみに絞る

"Condition": {
  "StringNotEquals": {
    "aws:RequestedRegion": ["ap-northeast-1"]
  }
}

Root ブロック: ArnLike + AssumedRoot 条件

"Condition": {
  "ArnLike": {
    "aws:PrincipalArn": "arn:aws:iam::*:root"
  },
  "Null": {
    "aws:AssumedRoot": "true"
  }
}

コンテンツタブで JSON を確認できます。

適用の過程で気付いたこと

適用時の気付き

  • 公式サンプルのなかでも StringLike と ArnLike が混在しており、AWS のポリシーエディタでは ArnLike 推奨の警告が出ました。エディタの検証は必ず通すのが実務上の正解と言えます
  • ルート認証情報ブロックで Null: aws:AssumedRoot = true が欠けていると、Organizations のルート一元管理機能自体が SCP で止まってしまいます
  • リージョン SCP の盲点: CloudFront / IAM 等のグローバル系は NotAction で救済されています。Lambda@Edge (us-east-1 の Lambda が必須)、DynamoDB Global Tables、S3 CRR など「他リージョンを伴う機能」を使う場合は、該当サービスを NotAction に追加してください (ap-northeast-1 単一運用なら現状のサンプルで十分)

Config の PutConfigurationRecorder / PutDeliveryChannel を Deny すると、Config の初期セットアップも塞がれます。
Control Tower などで組織管理している前提の構成です。メンバーアカウントで手動セットアップする運用では、Condition で管理者ロールを除外するか、該当 Action を外してください。

WorkloadsSCP (Workloads OU)

Workloads OU にのみアタッチする SCP です。

"Action": [
  "iam:CreateUser",
  "iam:CreateAccessKey",
  "iam:CreateLoginProfile"
]

元は CreateUser と CreateAccessKey だけでしたが、CreateLoginProfile を追加しました。
これがないと、IAM ユーザーの作成は塞げてもコンソールログイン用パスワードの付与で抜けられてしまいます。

まとめ

SCP を自己流で書くと「停止・削除」系だけに目が行きがちです。
Update* や Put* といった設定変更系まで塞いで、初めて "無効化防止" と呼べるガードレールになります。

AWS 公式サンプルは、SCP の "標準ライブラリ" として最初に目を通すのがおすすめです。
ただし鵜呑みにせず、ポリシーエディタの検証を通すことで、サンプル自体の微妙な齟齬にも気付けます。

そして、6 カテゴリを全て入れる必要はありません。
「なぜ入れる / 入れないか」を言語化できる状態こそが、ガードレールを自分の環境に合わせて育てる第一歩であると感じました。

今日も小さな学びを。

IAM Identity Center (& AWS Organizations) 関連記事

0
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
0
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?