IAM ポリシーの基本構造:Effect・Action・Resource・Condition の違いを完全解説
IAM ポリシーの JSON を初めて読んだとき、Effect・Action・Resource・Condition の四つの要素が何を制御しているのか、それぞれの境界がどこにあるのかが掴みにくい。本記事では、IAM ポリシーの基本構造を実際の運用経験をもとに解説し、よくある誤解と正しいモデルを整理する。
TL;DR:IAM ポリシー基本構造の早見表
| 要素 | 役割 | 必須 | 典型的な値の例 |
|---|---|---|---|
Effect | 許可か拒否かを決定する | ✅ | Allow / Deny |
Action | 対象の API アクションを指定する | ✅ | s3:GetObject |
Resource | アクションを適用するリソースを限定する | ✅ | arn:aws:s3:::my-bucket/* |
Condition | 追加の条件が満たされた場合のみ Statement を有効化する | ❌ | aws:SourceIp など |
IAM ポリシーの仕組み:評価モデルを理解する
IAM ポリシーは、AWS がリクエストを受け取ったときに評価される一連のルールセットだ。ポリシーは一つ以上の Statement で構成され、各 Statement が「誰が・何を・どのリソースに・どんな条件で・許可または拒否するか」を定義する。AWS はリクエストを評価する際、すべての適用可能なポリシーを収集し、以下の優先順位で判定する。
- デフォルト拒否:明示的な Allow がない限り、すべてのリクエストは暗黙的に拒否される。
- 明示的 Deny の優先:どのポリシーにも
Effect: Denyの Statement があれば、Allow があっても必ず拒否される。SCP(Service Control Policy)も同様のロジックで動作する。 - 明示的 Allow:Deny がなく、Allow が存在する場合のみアクセスが許可される。
「Explicit Deny は消せない壁だ。Allow をいくら積み上げても、Deny が一枚あれば全部無効になる。バケットポリシーと IAM ポリシーが両方存在する場合、どちらかに Deny があれば終わり。」
Effect:Allow か Deny か、それだけだが重要
IAM ポリシーの基本構造において、Effect は Statement の結論を決める要素だ。値は Allow と Deny の二択のみで、大文字小文字を区別する。
{
"Effect": "Allow"
}
運用上で重要なのは、Explicit Deny は Allow より常に優先されるという点だ。同一プリンシパルに対して複数のポリシーが適用されている場合(インラインポリシー、マネージドポリシー、バケットポリシー、SCP など)、どれか一つでも Effect: Deny の Statement がマッチすれば、そのリクエストは拒否される。
Deny を使うべき典型的なシナリオは、特定の IP アドレス範囲以外からの S3 アクセスを全面的にブロックしたい場合や、特定のリージョン外へのリソース作成を SCP で制限したい場合だ。
Action:どの API を許可・拒否するか
Action は、Statement が対象とする AWS API アクションを指定する。形式は サービスプレフィックス:アクション名 で、ワイルドカード(*)も使用できる。
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
]
}
"Action": "*" はすべての AWS サービスのすべての API を許可する。管理者ロールでも、これを使うのは最小権限の原則に反する。本番環境では必ず必要なアクションを列挙すること。
また、Action の代わりに NotAction を使うことで「指定したアクション以外すべて」という逆引き指定も可能だが、意図しない権限昇格につながりやすいため慎重に使う必要がある。
Resource:どのリソースに適用するか
Resource は、Action を適用するリソースを ARN で指定する。これが IAM ポリシーの基本構造の中で最も誤解されやすい要素だ。
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
S3 の場合、バケット操作(s3:ListBucket など)とオブジェクト操作(s3:GetObject など)では必要な ARN が異なる。s3:ListBucket はバケット自体(arn:aws:s3:::my-bucket)に対して指定し、s3:GetObject はオブジェクト(arn:aws:s3:::my-bucket/*)に対して指定する。この区別を間違えると、CLI でオブジェクトを取得しようとしたときに AccessDenied が返る。
一部の Read/List/Describe 系アクションはリソースレベルの権限をサポートしておらず、"Resource": "*" が必須になる。Service Authorization Reference で各アクションのリソースタイプサポートを必ず確認すること。
- バケットレベルの操作(ListBucket など)は、バケット ARN そのものを Resource に指定する。
- オブジェクトレベルの操作(GetObject・PutObject など)は、
/*サフィックス付きの ARN を指定する。 - リソースレベルの権限をサポートしないアクションは
*を使う。
Condition:条件付きアクセス制御の仕組み
Condition は、Statement を有効化するための追加条件を定義する。Condition が存在する場合、その条件が満たされたときのみ Statement が評価される。条件が満たされない場合、その Statement はスキップされる(Allow の場合は暗黙的拒否に戻る)。
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"198.51.100.0/24"
]
}
}
}
Condition の構造は 条件演算子 → 条件キー → 値 の三層になっている。上記の例では、IpAddress が演算子、aws:SourceIp がグローバル条件キー、IPアドレスのリストが値だ。
よく使われる条件キーのカテゴリを以下に示す。
| カテゴリ | 条件キーの例 | 用途 |
|---|---|---|
| グローバル条件キー | aws:SourceIp | 送信元 IP によるアクセス制限 |
| グローバル条件キー | aws:RequestedRegion | 特定リージョンへの操作を制限 |
| グローバル条件キー | aws:MultiFactorAuthPresent | MFA 認証済みリクエストのみ許可 |
| サービス固有 | s3:prefix | S3 プレフィックスによるアクセス制限 |
| サービス固有 | iam:PassedToService | ロールの渡し先サービスを制限 |
Condition の評価で注意が必要なのは、条件キーが存在しない場合の挙動だ。条件キーがリクエストコンテキストに含まれていない場合、条件演算子によって評価結果が変わる。StringEquals などの通常の演算子は条件キーが存在しない場合に false を返すが、...IfExists サフィックス付きの演算子(例:StringEqualsIfExists)はキーが存在しない場合に true を返す。この違いを理解していないと、意図しないアクセス拒否やアクセス許可が発生する。
完全な Statement の例:四要素を組み合わせる
実際のポリシーでは、複数の Statement を組み合わせて必要な権限セットを表現する。以下は、特定の S3 バケットへの読み取りアクセスを MFA 認証済みリクエストに限定するポリシーの例だ。
🔽 完全な IAM ポリシー JSON(クリックして展開)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-secure-bucket",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "AllowGetObject",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-secure-bucket/*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "DenyNonMFAAccess",
"Effect": "Deny",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-secure-bucket",
"arn:aws:s3:::my-secure-bucket/*"
],
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
三番目の Statement で BoolIfExists を使っているのは、MFA コンテキストが存在しない場合(例:アクセスキーによる直接 API 呼び出し)も確実に拒否するためだ。Bool だけでは、コンテキストキーが存在しない場合に条件が false になり、Deny が適用されない。
よくある誤診:AccessDenied の原因を間違える
本番環境で頻繁に遭遇するパターンを一つ挙げる。
症状: IAM ポリシーに s3:GetObject の Allow を追加したのに、AccessDenied が解消されない。
誤診: ポリシーの反映に時間がかかっているのだろう、と待ち続ける。または Resource の ARN が間違っていると思い込んで修正を繰り返す。
実際の原因: S3 バケットポリシーに明示的 Deny が設定されていた。IAM ポリシーで Allow を追加しても、バケットポリシーの Explicit Deny が優先されるため、アクセスは永遠に拒否される。IAM ポリシーとリソースベースポリシー(バケットポリシー)の両方を確認しないと、この問題は解決しない。
修正手順:
# バケットポリシーを確認して Deny Statement がないかチェックする
aws s3api get-bucket-policy \
--bucket my-secure-bucket \
--query Policy \
--output text
# IAM ポリシーのシミュレーションで評価結果を確認する
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/example-user \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-secure-bucket/example-key.txt
simulate-principal-policy の出力に implicitDeny と explicitDeny が含まれる。explicitDeny が返った場合は、どのポリシーが Deny を発行しているかを MatchedStatements フィールドで確認できる。
IAM ポリシー構造の検証:実用的な CLI コマンド
ポリシーを書いたら、デプロイ前に構文と意図を検証する習慣をつけること。IAM Policy Validator は構文エラーと一部のセマンティックエラーを検出できる。
# ポリシードキュメントの構文を検証する
aws accessanalyzer validate-policy \
--policy-document file://my-policy.json \
--policy-type IDENTITY_POLICY
--policy-type には IDENTITY_POLICY(IAM ポリシー)または RESOURCE_POLICY(リソースベースポリシー)を指定する。このコマンドは IAM Access Analyzer を使用するため、対象リージョンで Access Analyzer が有効になっている必要がある。
# 既存のマネージドポリシーの内容を確認する
aws iam get-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/MyPolicy \
--version-id v1 \
--query 'PolicyVersion.Document' \
--output json
IAM ポリシーの基本構造:まとめと次のステップ
IAM ポリシーの基本構造を理解するうえで核心となるのは、Effect・Action・Resource の三要素が Statement の骨格を形成し、Condition がその適用条件を絞り込むという関係性だ。Explicit Deny は常に Allow より優先され、バケットポリシーや SCP など複数のポリシーレイヤーが存在する環境では、どのレイヤーで拒否が発生しているかを特定することが AccessDenied のトラブルシューティングの出発点になる。
- IAM Policy Simulator を使って、実際のリクエストコンテキストでポリシーを検証する
- AWS Service Authorization Reference で各アクションのリソースレベル権限サポートを確認する
- IAM Access Analyzer を有効化して、外部エンティティからのアクセスを継続的に監視する
公式ドキュメント:IAM JSON ポリシー要素リファレンス
用語集
| 用語 | 説明 |
|---|---|
| Statement | IAM ポリシーを構成する個々のルールブロック。Effect・Action・Resource・Condition を含む。 |
| Explicit Deny | ポリシー内で明示的に指定された拒否。Allow より常に優先される。 |
| ARN(Amazon Resource Name) | AWS リソースを一意に識別する識別子。形式は arn:aws:<service>:<region>:<account-id>:<resource>。 |
| 条件演算子 | Condition ブロックで使用する比較演算子。StringEquals・IpAddress・Bool など。 |
| 最小権限の原則 | 必要最小限の権限のみを付与するセキュリティ設計原則。IAM 設計の基本。 |
コメント
コメントを投稿