- AWS
IAMポリシーConditionの書き方|条件演算子と条件キー一覧
IAMポリシーの Condition とは、「どんなときにそのステートメントを効かせるか」を、条件演算子・条件キー・値の3つの組み合わせで書く要素です。たとえば「接続元の IP アドレスがこの範囲のとき」「MFA で認証しているとき」「タグが一致するとき」といった条件を付けられます。
この記事では、条件演算子の全一覧表と、よく使うグローバル条件キーの早見表をまず示し、そのあとで「複数の条件は AND か OR か」「キーが無いときはどう判定されるか」という、つまずきやすい2つの規則を図と真理値表で整理します。コピーして使える JSON も10本用意しました。
確認環境:Ubuntu 24.04、Python 3.11、AWS CLI 1.46.1。評価規則は AWS IAM ユーザーガイドの記述をもとにし、その規則を Python で書き写した小さな評価器で、ガイドに載っている評価例の表 24 件と同じ結果になることを確かめています。掲載した JSON 10本は、AWS の API をローカルで再現するツール(moto 5.2.3)に登録して、文法が通ることを確かめました。
Condition の早見表
基本の形
"Condition": {
"条件演算子": {
"条件キー": "値"
}
}
読み方は「条件キーの値を、条件演算子のやり方で、値と比べる」です。次の例は「リクエスト先のリージョン(aws:RequestedRegion)が、文字列として ap-northeast-1 に等しい(StringEquals)とき」という意味になります。
"Condition": {
"StringEquals": { "aws:RequestedRegion": "ap-northeast-1" }
}
評価規則の早見表
| 書き方 | 判定 |
|---|---|
| 条件演算子を複数並べる | すべて満たすとき(AND) |
| 1つの演算子の中に条件キーを複数並べる | すべて満たすとき(AND) |
| 1つの条件キーに値を配列で複数書く | どれか1つに一致すればよい(OR) |
| 否定の演算子(StringNotEquals など)に値を複数書く | どれにも一致しないとき(NOR) |
| リクエストに条件キーが無い(肯定の演算子) | 条件は false |
| リクエストに条件キーが無い(否定の演算子) | 条件は true |
| リクエストに条件キーが無い(~IfExists) | 条件は true |
| Null 演算子 | キーが無いことを "true"、有ることを "false" で調べる |
やりたいこと別の組み合わせ
| やりたいこと | 条件演算子 | 条件キー |
|---|---|---|
| 接続元 IP で絞る | IpAddress / NotIpAddress | aws:SourceIp |
| VPC エンドポイント経由だけにする | StringEquals / StringNotEquals | aws:SourceVpce |
| MFA を必須にする | BoolIfExists | aws:MultiFactorAuthPresent |
| MFA 認証からの経過時間で絞る | NumericLessThan | aws:MultiFactorAuthAge |
| リソースのタグで絞る | StringEquals | aws:ResourceTag/タグキー |
| 利用者のタグとリソースのタグを突き合わせる | StringEquals | aws:ResourceTag/タグキー と ${aws:PrincipalTag/タグキー} |
| 作成時のタグを決める | StringEquals、ForAllValues:StringEquals | aws:RequestTag/タグキー、aws:TagKeys |
| リージョンを絞る | StringEquals / StringNotEquals | aws:RequestedRegion |
| 期間を絞る | DateGreaterThan / DateLessThan | aws:CurrentTime |
| HTTPS だけにする | Bool | aws:SecureTransport |
| 一時的な認証情報だけにする | Null | aws:TokenIssueTime |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IAMポリシーConditionの書き方|条件演算子と条件キー一覧」
条件演算子の全一覧
AWS IAM ユーザーガイドの「条件演算子」のページに沿って、型ごとにまとめます。
文字列
| 条件演算子 | 意味 |
|---|---|
| StringEquals | 完全一致(大文字と小文字を区別する) |
| StringNotEquals | 一致しない |
| StringEqualsIgnoreCase | 完全一致(大文字と小文字を区別しない) |
| StringNotEqualsIgnoreCase | 一致しない(大文字と小文字を区別しない) |
| StringLike | ワイルドカードつきの一致。* は0文字以上、? は1文字。大文字と小文字を区別する |
| StringNotLike | ワイルドカードつきで一致しない |
部分一致をしたいときは StringLike を使い、ワイルドカードを明示します。文字列の演算子では、値に ${aws:username} のようなポリシー変数を書けます。
数値
| 条件演算子 | 意味 |
|---|---|
| NumericEquals | 等しい |
| NumericNotEquals | 等しくない |
| NumericLessThan | より小さい |
| NumericLessThanEquals | 以下 |
| NumericGreaterThan | より大きい |
| NumericGreaterThanEquals | 以上 |
日付
| 条件演算子 | 意味 |
|---|---|
| DateEquals | その日時に等しい |
| DateNotEquals | その日時に等しくない |
| DateLessThan | その日時より前 |
| DateLessThanEquals | その日時以前 |
| DateGreaterThan | その日時より後 |
| DateGreaterThanEquals | その日時以後 |
aws:CurrentTime や aws:EpochTime と組み合わせます。値は ISO 8601 形式(例:2026-10-01T00:00:00Z)か、エポック秒で書きます。
Bool・バイナリ
| 条件演算子 | 意味 |
|---|---|
| Bool | true / false の一致 |
| BinaryEquals | バイナリ値の一致(値は Base64 で書く) |
IP アドレス
| 条件演算子 | 意味 |
|---|---|
| IpAddress | 指定した IP アドレスまたは範囲に入っている |
| NotIpAddress | 指定した IP アドレスまたは範囲に入っていない |
値は CIDR 形式(例:203.0.113.0/24、2001:DB8:1234:5678::/64)で書きます。プレフィックスを省くと /32 として扱われます。
ARN
| 条件演算子 | 意味 |
|---|---|
| ArnEquals、ArnLike | ARN の一致。コロンで区切った6つの部分ごとに比べ、* と ? が使える。2つは同じ動きをする |
| ArnNotEquals、ArnNotLike | ARN が一致しない。2つは同じ動きをする |
キーの有無を調べる:Null
| 書き方 | 意味 |
|---|---|
"Null": { "キー": "true" } |
リクエストにそのキーが無い |
"Null": { "キー": "false" } |
リクエストにそのキーが有り、値が入っている |
末尾に付ける:IfExists
IfExists は、Null 以外のどの演算子にも末尾に付けられます(StringEqualsIfExists、BoolIfExists、NotIpAddressIfExists など)。意味は「キーが有れば普通に比べる。キーが無ければ、その条件は true とする」です。
先頭に付ける:ForAllValues と ForAnyValue
aws:TagKeys のように、1回のリクエストで複数の値を持つ条件キー(複数値のキー)には、演算子の先頭に次のどちらかを付けます。
| 修飾子 | 意味 | キーが無いとき |
|---|---|---|
| ForAllValues: | リクエストの値がすべて、ポリシーの値のどれかに一致する | true(空の集合は「すべて一致」と見なされる) |
| ForAnyValue: | リクエストの値のどれか1つが、ポリシーの値のどれかに一致する | false |
ForAllValues を Allow で使うときは、Null の "false" を組み合わせて「キーが有ること」も条件にします。キーが無いリクエストまで許可してしまうことを防ぐためで、ユーザーガイドでも勧められている書き方です。
"Condition": {
"ForAllValues:StringEquals": { "aws:TagKeys": ["environment", "cost-center"] },
"Null": { "aws:TagKeys": "false" }
}
aws:ResourceTag/タグキー のように値が1つだけのキー(単一値のキー)には、この修飾子は付けません。
型ごとの対応表
| 型 | ワイルドカード | ポリシー変数 | 主な条件キーの例 |
|---|---|---|---|
| 文字列 | StringLike 系で使える | 使える | aws:RequestedRegion、aws:PrincipalTag/キー |
| 数値 | 使えない | 使えない | aws:MultiFactorAuthAge |
| 日付 | 使えない | 使えない | aws:CurrentTime、aws:TokenIssueTime |
| Bool | 使えない | 使える | aws:SecureTransport、aws:MultiFactorAuthPresent |
| IP アドレス | 使えない(CIDR で範囲を書く) | 使えない | aws:SourceIp |
| ARN | 使える | 使える | aws:PrincipalArn、aws:SourceArn |
よく使うグローバル条件キーの早見表
「aws:」で始まるキーは、サービスをまたいで使えるグローバル条件キーです。「リクエストに含まれるとき」の列が大切で、含まれない場面があるキーは、あとで説明する「キーが無いとき」の規則に関わります。
接続元(ネットワーク)
| 条件キー | 型 | 内容 | リクエストに含まれるとき |
|---|---|---|---|
| aws:SourceIp | IP アドレス | リクエスト元の IP アドレス | VPC エンドポイント経由のリクエストには含まれない |
| aws:VpcSourceIp | IP アドレス | VPC の中でのリクエスト元 IP アドレス | VPC エンドポイント経由のとき |
| aws:SourceVpc | 文字列 | 経由した VPC の ID | VPC エンドポイント経由のときだけ |
| aws:SourceVpce | 文字列 | 経由した VPC エンドポイントの ID | VPC エンドポイント経由のときだけ |
| aws:SecureTransport | Bool | SSL/TLS で送られたか | 常に含まれる |
認証の状態
| 条件キー | 型 | 内容 | リクエストに含まれるとき |
|---|---|---|---|
| aws:MultiFactorAuthPresent | Bool | 一時的な認証情報が MFA を使って発行されたか | 一時的な認証情報を使うときだけ。アクセスキーで署名した CLI・API・SDK のリクエストには含まれない |
| aws:MultiFactorAuthAge | 数値 | MFA で認証してからの秒数 | 一時的な認証情報を使うときだけ |
| aws:TokenIssueTime | 日付 | 一時的な認証情報が発行された日時 | 一時的な認証情報を使うときだけ |
利用者(プリンシパル)
| 条件キー | 型 | 内容 | リクエストに含まれるとき |
|---|---|---|---|
| aws:PrincipalTag/タグキー | 文字列 | リクエストした利用者に付いているタグ | ユーザーやロールにタグが付いているとき、またはセッションタグがあるとき |
| aws:PrincipalArn | ARN | リクエストした利用者の ARN | 署名つきのリクエストすべて |
| aws:PrincipalAccount | 文字列 | 利用者が属するアカウント | すべてのリクエスト |
| aws:PrincipalOrgID | 文字列 | 利用者が属する組織(AWS Organizations)の ID | 利用者が組織のメンバーのとき |
| aws:PrincipalType | 文字列 | 利用者の種類 | すべてのリクエスト |
| aws:username | 文字列 | IAM ユーザー名 | IAM ユーザーのとき(ロールやルートユーザーには無い) |
| aws:userid | 文字列 | 利用者の一意の ID | すべてのリクエスト |
| aws:PrincipalIsAWSService | Bool | AWS のサービス自身による呼び出しか | 署名つきのリクエストすべて |
リクエストの内容とリソース
| 条件キー | 型 | 内容 | リクエストに含まれるとき |
|---|---|---|---|
| aws:RequestedRegion | 文字列 | リクエスト先のリージョン | リージョンを持つリクエスト |
| aws:CurrentTime | 日付 | 現在の日時 | 常に含まれる |
| aws:EpochTime | 数値(エポック秒) | 現在の日時 | 常に含まれる |
| aws:RequestTag/タグキー | 文字列 | リクエストで指定したタグの値 | リクエストでタグを指定したとき |
| aws:TagKeys | 文字列(複数値) | リクエストで指定したタグキーの一覧 | リクエストでタグを指定したとき |
| aws:ResourceTag/タグキー | 文字列 | 操作対象のリソースに付いているタグ | 対象のリソースにタグがあるとき |
| aws:ResourceAccount | 文字列 | リソースが属するアカウント | リクエストに含まれる |
| aws:ResourceOrgID | 文字列 | リソースが属する組織の ID | リクエストに含まれる |
| aws:SourceArn | ARN | AWS のサービスが呼び出すとき、きっかけになったリソースの ARN | AWS のサービスが直接呼び出すときだけ |
| aws:SourceAccount | 文字列 | AWS のサービスが呼び出すとき、きっかけになったリソースのアカウント | AWS のサービスが直接呼び出すときだけ |
| aws:CalledVia | 文字列(複数値) | リクエストが経由した AWS サービスの一覧 | AWS サービスを経由したとき |
| aws:ViaAWSService | Bool | AWS サービスを経由したリクエストか | AWS サービスを経由したとき |
| aws:UserAgent | 文字列 | ユーザーエージェント | 常に含まれる |
このほかに、s3:prefix や ec2:InstanceType のような、サービスごとの条件キーがあります。使えるキーは操作やリソースの種類によって決まっています。
複数条件の評価規則:AND と OR
規則は2つだけです。
- 演算子どうし、条件キーどうしは AND(全部を満たす必要がある)
- 1つの条件キーに書いた複数の値は OR(どれか1つに一致すればよい)
flowchart TD
C["Condition(すべて AND)"] --> O1["StringEquals"]
C --> O2["IpAddress"]
O1 --> K1["aws:PrincipalTag/team<br>(値どうしは OR)"]
O1 --> K2["aws:RequestedRegion<br>(値どうしは OR)"]
O2 --> K3["aws:SourceIp<br>(値どうしは OR)"]
K1 --> V1["web"]
K1 --> V2["data"]
K2 --> V3["ap-northeast-1"]
K2 --> V4["ap-northeast-3"]
K3 --> V5["203.0.113.0/24"]
図を JSON にすると、次のとおりです。
"Condition": {
"StringEquals": {
"aws:PrincipalTag/team": ["web", "data"],
"aws:RequestedRegion": ["ap-northeast-1", "ap-northeast-3"]
},
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
これは「(team が web または data)かつ(リージョンが東京 または 大阪)かつ(接続元が 203.0.113.0/24 の中)」という意味です。
| team | リージョン | 接続元 IP | 条件 |
|---|---|---|---|
| web | ap-northeast-1 | 203.0.113.25 | true(3つとも満たす) |
| data | ap-northeast-3 | 203.0.113.25 | true |
| web | us-east-1 | 203.0.113.25 | false(リージョンが合わない) |
| web | ap-northeast-1 | 198.51.100.7 | false(IP が合わない) |
| タグなし | ap-northeast-1 | 203.0.113.25 | false(キーが無い) |
否定の演算子に複数の値を書くと「どれにも一致しない」
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["ap-northeast-1", "ap-northeast-3"]
}
}
これは「東京でも大阪でもない」ときに true になります。「東京ではない、または、大阪ではない」(=いつも true)にはならないので、否定の演算子に許可したい値を並べる書き方は、そのまま「それ以外」を表せます。
同じ演算子は1回だけ書く
JSON では、同じ階層に同じ名前のキーを2回書けません。同じ演算子で複数の条件キーを調べたいときは、1つの演算子の中にまとめます。
"Condition": {
"StringEquals": {
"aws:PrincipalTag/team": "web",
"aws:RequestedRegion": "ap-northeast-1"
}
}
「同じキーについて、ある日時以後かつ別の日時より前」のように、同じ条件キーに2つの比較をしたいときは、DateGreaterThanEquals と DateLessThan のように、演算子を分けて書きます(コピペ用 JSON の 8 を参照)。
キーが無いときの評価:Deny と BoolIfExists の真理値表
条件キーは、いつもリクエストに含まれるとは限りません。たとえば aws:MultiFactorAuthPresent は、アクセスキーで署名した CLI のリクエストには含まれません。このときの判定は、ユーザーガイドで次のように決められています。
| 演算子の種類 | キーが無いときの条件の結果 |
|---|---|
| 肯定の演算子(StringEquals、Bool、IpAddress、NumericLessThan など) | false |
| 否定の演算子(StringNotEquals、NotIpAddress、ArnNotLike など) | true |
| ~IfExists を付けた演算子 | true |
| ForAllValues: を付けた演算子 | true |
| ForAnyValue: を付けた演算子 | false |
| Null | "true" と書いていれば true、"false" と書いていれば false |
これを「MFA を必須にする」書き方に当てはめると、次の真理値表になります。列は、リクエストに含まれる aws:MultiFactorAuthPresent の状態です。
| Effect | 条件 | true(MFA あり) | false(MFA なし) | キーなし(アクセスキーなど) |
|---|---|---|---|---|
| Deny | "Bool": {"aws:MultiFactorAuthPresent": "false"} |
拒否しない | 拒否する | 拒否しない |
| Deny | "BoolIfExists": {"aws:MultiFactorAuthPresent": "false"} |
拒否しない | 拒否する | 拒否する |
| Allow | "Bool": {"aws:MultiFactorAuthPresent": "true"} |
許可する | 許可しない | 許可しない |
| Allow | "BoolIfExists": {"aws:MultiFactorAuthPresent": "true"} |
許可する | 許可しない | 許可する |
読み取れることは3つあります。
- Deny で MFA を必須にするなら BoolIfExists と "false" の組み合わせを使う。Bool だけだと、キーが無いリクエスト(アクセスキーでの呼び出し)は条件が false になり、拒否の対象から外れる
- Allow で MFA を条件にするなら、IfExists を付けない Bool と "true"を使う。BoolIfExists にすると、キーが無いリクエストまで許可される
- 迷ったら「キーが無いリクエストを、拒否したいのか、通したいのか」を先に決め、上の表から選ぶ
ユーザーガイドも、MFA の確認には Deny・BoolIfExists・false の組み合わせを勧めており、この形は MFA なしの一時的な認証情報と、アクセスキーなどの長期の認証情報によるリクエストの両方を拒否する、と説明しています。
評価規則を手元で試す:Python の小さな評価器
規則を文章で覚えるより、値を変えて試したほうが早く身に付きます。ここまでの規則を Python に書き写した、学習用の評価器を載せます。実際の判定は AWS の側で行われるもので、これは規則を理解するための道具です。cond_eval.py として保存します。
"""IAM の Condition の評価規則を、公式ドキュメントの記述どおりに写した学習用の評価器。
context は {条件キー: 値 または 値のリスト}。キーが無い = リクエストにその情報が含まれない。"""
import ipaddress
import re
from datetime import datetime
def _like(pattern, value):
# * は0文字以上、? は1文字に一致
rx = "".join(".*" if c == "*" else "." if c == "?" else re.escape(c) for c in pattern)
return re.fullmatch(rx, value) is not None
def _arn(pattern, value):
p, v = pattern.split(":", 5), value.split(":", 5)
return len(p) == len(v) and all(_like(a, b) for a, b in zip(p, v))
def _date(s):
return datetime.fromisoformat(str(s).replace("Z", "+00:00"))
def _bool(s):
return str(s).lower() == "true"
# 演算子名 -> (1つの値どうしを比べる関数, 否定の演算子か)
OPS = {
"StringEquals": (lambda p, v: p == v, False),
"StringNotEquals": (lambda p, v: p == v, True),
"StringEqualsIgnoreCase": (lambda p, v: p.lower() == v.lower(), False),
"StringNotEqualsIgnoreCase": (lambda p, v: p.lower() == v.lower(), True),
"StringLike": (_like, False),
"StringNotLike": (_like, True),
"NumericEquals": (lambda p, v: float(v) == float(p), False),
"NumericNotEquals": (lambda p, v: float(v) == float(p), True),
"NumericLessThan": (lambda p, v: float(v) < float(p), False),
"NumericLessThanEquals": (lambda p, v: float(v) <= float(p), False),
"NumericGreaterThan": (lambda p, v: float(v) > float(p), False),
"NumericGreaterThanEquals": (lambda p, v: float(v) >= float(p), False),
"DateEquals": (lambda p, v: _date(v) == _date(p), False),
"DateNotEquals": (lambda p, v: _date(v) == _date(p), True),
"DateLessThan": (lambda p, v: _date(v) < _date(p), False),
"DateLessThanEquals": (lambda p, v: _date(v) <= _date(p), False),
"DateGreaterThan": (lambda p, v: _date(v) > _date(p), False),
"DateGreaterThanEquals": (lambda p, v: _date(v) >= _date(p), False),
"Bool": (lambda p, v: _bool(p) == _bool(v), False),
"IpAddress": (lambda p, v: ipaddress.ip_address(v) in ipaddress.ip_network(p, strict=False), False),
"NotIpAddress": (lambda p, v: ipaddress.ip_address(v) in ipaddress.ip_network(p, strict=False), True),
"ArnEquals": (_arn, False),
"ArnLike": (_arn, False),
"ArnNotEquals": (_arn, True),
"ArnNotLike": (_arn, True),
}
def _as_list(x):
return x if isinstance(x, list) else [x]
def test_key(operator, key, policy_values, context):
"""1つの演算子・1つの条件キーの判定"""
policy_values = _as_list(policy_values)
present = key in context
if operator == "Null": # "true" = キーが無い、"false" = キーが有る
return _bool(policy_values[0]) == (not present)
qualifier = None
if ":" in operator: # ForAllValues: / ForAnyValue:
qualifier, operator = operator.split(":", 1)
if_exists = operator.endswith("IfExists")
if if_exists:
operator = operator[: -len("IfExists")]
match, negated = OPS[operator]
if not present:
if if_exists:
return True # IfExists:キーが無ければ true
if qualifier == "ForAllValues":
return True # 空の集合は「すべて一致」とみなされる
if qualifier == "ForAnyValue":
return False
return negated # 肯定の演算子は false、否定の演算子は true
def hit(v): # リクエストの値1つが、ポリシーの値のどれかに一致するか(OR)
return any(match(p, v) for p in policy_values)
values = _as_list(context[key])
if qualifier == "ForAllValues":
return all(hit(v) != negated for v in values)
if qualifier == "ForAnyValue":
return any(hit(v) != negated for v in values)
return hit(values[0]) != negated # 否定の演算子は「どれにも一致しない」(NOR)
def evaluate(condition, context):
"""Condition ブロック全体:演算子どうし、キーどうしはすべて AND"""
return all(
test_key(op, key, vals, context)
for op, keys in condition.items()
for key, vals in keys.items()
)
使い方
from cond_eval import evaluate
condition = {
"StringEquals": {"aws:RequestedRegion": ["ap-northeast-1", "ap-northeast-3"]},
"IpAddress": {"aws:SourceIp": "203.0.113.0/24"},
}
print(evaluate(condition, {"aws:RequestedRegion": "ap-northeast-3", "aws:SourceIp": "203.0.113.25"}))
print(evaluate(condition, {"aws:RequestedRegion": "us-east-1", "aws:SourceIp": "203.0.113.25"}))
print(evaluate(condition, {"aws:RequestedRegion": "ap-northeast-1", "aws:SourceIp": "198.51.100.7"}))
print(evaluate(condition, {"aws:RequestedRegion": "ap-northeast-1"}))
True
False
False
False
1行目は両方の条件を満たす場合、2行目はリージョンが合わない場合、3行目は IP が合わない場合、4行目は aws:SourceIp が無い場合です。
ユーザーガイドの評価例と突き合わせる
ユーザーガイドには、条件とリクエストの組み合わせごとに「一致する/しない」を示した表が載っています。AND と OR の例、否定の演算子の例、IfExists の例、ForAllValues と ForAnyValue の例、あわせて 24 件を評価器に通したところ、すべて同じ結果になりました。
AND/OR 1 評価器=True ドキュメント=True 一致
AND/OR 2 評価器=False ドキュメント=False 一致
…(省略)…
IfExists 3 評価器=True ドキュメント=True 一致
ForAllValues 1 評価器=True ドキュメント=True 一致
…(省略)…
ForAnyValue 6 評価器=False ドキュメント=False 一致
24/24 件が一致
前の章の真理値表も、この評価器で {"Bool": {...}} と {"BoolIfExists": {...}} を、キーの有無を変えながら評価して作ったものです。
Effect | 演算子 | 値 | true | false | キーなし
Deny | Bool | false | 拒否しない | 拒否する | 拒否しない
Deny | BoolIfExists | false | 拒否しない | 拒否する | 拒否する
Allow | Bool | true | 許可する | 許可しない | 許可しない
Allow | BoolIfExists | true | 許可する | 許可しない | 許可する
AWS のシミュレーターで確かめる
AWS の側で判定を確かめたいときは、aws iam simulate-custom-policy が使えます。--context-entries で条件キーの値を渡せるので、Condition の動きを、実際に操作を行わずに調べられます。AWS CLI のリファレンスに載っている例は次のとおりです。
aws iam simulate-custom-policy \
--policy-input-list '{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"dynamodb:*","Resource":"*","Condition":{"DateGreaterThan":{"aws:CurrentTime":"2018-08-16T12:00:00Z"}}}}' \
--action-names dynamodb:CreateBackup \
--context-entries "ContextKeyName='aws:CurrentTime',ContextKeyValues='2019-04-25T11:00:00Z',ContextKeyType=date"
リファレンスの出力例では、EvalDecision が allowed になっています。EvalDecision の値は allowed(許可)、explicitDeny(明示的な拒否)、implicitDeny(許可が無いための拒否)の3種類です。ContextKeyType には string、stringList、numeric、boolean、ip、date などを指定します。
コピペ用 JSON 10本
バケット名、IP アドレス、ID などは例の値です。自分の環境の値に置き換えて使います。各 JSON の下に、Condition を上の評価器に通した結果を「リクエストの情報 → 条件の結果」の形で添えました。Deny のステートメントでは true が「拒否する」、Allow では true が「許可の対象になる」を表します。
1. IP 制限:決めた範囲の外からの操作を拒否する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyOutsideOffice",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"2001:db8:1234:5678::/64"
]
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| SourceIp=203.0.113.25 | false(拒否しない) |
| SourceIp=198.51.100.7 | true(拒否する) |
| SourceIp=2001:db8:1234:5678::1 | false(拒否しない) |
| キーなし | true(拒否する) |
NotIpAddress は否定の演算子なので、aws:SourceIp が無いリクエストも拒否の対象になります。VPC エンドポイント経由のリクエストには aws:SourceIp が含まれないため、VPC の中からも使う場合は、次の 2 のように aws:SourceVpce を使う条件と使い分けます。また、ユーザーガイドには、AWS のサービスが代わりに行う呼び出しを Deny で止めてしまわないよう、aws:PrincipalIsAWSService が false であることを条件に加える方法が紹介されています。
2. IP 制限(VPC 版):決めた VPC エンドポイント経由だけにする
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyOutsideVpce",
"Effect": "Deny",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-report-bucket",
"arn:aws:s3:::example-report-bucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-0123456789abcdef0"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| SourceVpce=vpce-0123456789abcdef0 | false(拒否しない) |
| SourceVpce=vpce-0fedcba9876543210 | true(拒否する) |
| キーなし(インターネット経由) | true(拒否する) |
3. MFA 必須:停止と削除は MFA で認証したときだけ
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyStopWithoutMfa",
"Effect": "Deny",
"Action": [
"ec2:StopInstances",
"ec2:TerminateInstances"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| MultiFactorAuthPresent=true | false(拒否しない) |
| MultiFactorAuthPresent=false | true(拒否する) |
| キーなし | true(拒否する) |
このステートメントは拒否だけを定めています。操作そのものの許可は、別の Allow のステートメントで与えます。
4. MFA 必須(時間つき):MFA 認証から1時間以内だけ許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowWithinOneHourOfMfa",
"Effect": "Allow",
"Action": "ec2:TerminateInstances",
"Resource": "*",
"Condition": {
"NumericLessThan": {
"aws:MultiFactorAuthAge": "3600"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| MultiFactorAuthAge=600 | true(許可の対象) |
| MultiFactorAuthAge=7200 | false |
| キーなし | false |
NumericLessThan は肯定の演算子なので、キーが無いリクエストは許可の対象になりません。
5. タグ一致:自分と同じ team タグのインスタンスだけ起動・停止できる
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSameTeam",
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/team": "${aws:PrincipalTag/team}"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| 利用者の team=web、リソースの team=web | true(許可の対象) |
| 利用者の team=web、リソースの team=data | false |
${aws:PrincipalTag/team} はポリシー変数で、評価のときに利用者のタグの値に置き換えられます。チームが増えてもポリシーを書き足さずに済むのが、この書き方の良いところです。
6. タグ一致(作成時):決めたタグを付けたときだけ作成できる
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCreateWithTags",
"Effect": "Allow",
"Action": "ec2:CreateVolume",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/env": [
"dev",
"stg"
]
},
"ForAllValues:StringEquals": {
"aws:TagKeys": [
"env",
"team"
]
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| RequestTag/env=dev、TagKeys=[env, team] | true(許可の対象) |
| RequestTag/env=prod、TagKeys=[env] | false(env の値が合わない) |
| RequestTag/env=dev、TagKeys=[env, owner] | false(決めていないタグキーがある) |
| キーなし(タグを付けていない) | false |
StringEquals が「env タグの値は dev か stg」、ForAllValues:StringEquals が「付けてよいタグキーは env と team だけ」を表します。aws:RequestTag/env の条件があるので、タグを付けないリクエストは許可の対象になりません。
7. リージョン制限:東京と大阪以外での操作を拒否する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyOutsideJapan",
"Effect": "Deny",
"NotAction": [
"iam:*",
"sts:*",
"support:*",
"cloudfront:*",
"route53:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"ap-northeast-1",
"ap-northeast-3"
]
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| RequestedRegion=ap-northeast-1 | false(拒否しない) |
| RequestedRegion=ap-northeast-3 | false(拒否しない) |
| RequestedRegion=us-east-1 | true(拒否する) |
IAM や CloudFront のように、リージョンを選ばずに使うサービスは NotAction で対象から外しています。外すサービスは、使っているものに合わせて見直します。
8. 期間限定:2026年10月の間だけ読み取りを許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDuringOctober",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-report-bucket/*",
"Condition": {
"DateGreaterThanEquals": {
"aws:CurrentTime": "2026-09-30T15:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2026-10-31T15:00:00Z"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| CurrentTime=2026-10-05T06:00:00Z | true(許可の対象) |
| CurrentTime=2026-09-30T14:59:59Z | false(開始前) |
| CurrentTime=2026-10-31T15:00:00Z | false(終了後) |
日時は UTC で書いています。日本時間の 10月1日 0:00 は、UTC では 9月30日 15:00 です。始まりと終わりを、別々の演算子(DateGreaterThanEquals と DateLessThan)に分けて書くのがポイントです。
9. HTTPS 必須:暗号化されていない接続を拒否する(バケットポリシー)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyHttp",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-report-bucket",
"arn:aws:s3:::example-report-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| SecureTransport=true | false(拒否しない) |
| SecureTransport=false | true(拒否する) |
これは S3 のバケットポリシー(リソースに付けるポリシー)なので、Principal を書いています。
10. 一時的な認証情報だけ許可する(Null の例)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyTemporaryCredentials",
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*",
"Condition": {
"Null": {
"aws:TokenIssueTime": "false"
}
}
}
]
}
| リクエストの情報 | 条件の結果 |
|---|---|
| TokenIssueTime=2026-10-05T05:00:00Z | true(許可の対象) |
| キーなし(アクセスキーなどの長期の認証情報) | false |
aws:TokenIssueTime は一時的な認証情報を使うときだけ含まれるので、「キーが有ること」(Null が "false")を条件にすると、ロールなどの一時的な認証情報による操作だけを許可できます。
つまずきやすい点のチェックリスト
| 確認すること | 理由 |
|---|---|
| 演算子の名前のつづりと大文字・小文字 | StringEquals、IpAddress、ArnLike など、決まった名前で書く |
| 同じ演算子を2回書いていないか | JSON のキーは重複できない。1つの演算子の中にまとめる |
| Bool の値を引用符つきの文字列で書いたか | "true" / "false" と書く |
| 否定の演算子で、キーが無い場合を考えたか | キーが無いと true になる |
| Deny で「キーが無いリクエスト」も止めたいか | 止めたいなら IfExists を付ける |
| Allow に IfExists を付けていないか | キーが無いリクエストまで許可の対象になる |
| ForAllValues を Allow で使うとき、Null の "false" を添えたか | キーが無いと true になる |
| 部分一致に StringLike とワイルドカードを使ったか | StringEquals は完全一致 |
| その条件キーが、対象の操作で使えるか | サービスごとの条件キーは、操作やリソースの種類で決まっている |
よくある質問
Q. Condition の中で OR を書くには、どうすればよいですか? A. 同じ条件キーについての OR は、値を配列で並べます。別々の条件キーについての OR(A または B)は、1つの Condition の中では書けないので、ステートメントを2つに分けます。ステートメントどうしは、どれか1つが当てはまれば効くためです。
Q. StringEquals と StringLike は、どう使い分けますか? A. 値がはっきり決まっているときは StringEquals、前方一致などの部分一致をしたいときは StringLike とワイルドカードを使います。
Q. IfExists は、どんなときに付けますか? A. 「キーが有るときだけ比べたい」ときです。1つのステートメントが複数の種類のリソースにまたがっていて、一部のリソースにしか無い条件キーを使う場合や、Deny でキーが無いリクエストも止めたい場合に使います。
Q. 書いた Condition が思ったとおりに効くか、確かめる方法はありますか?
A. aws iam simulate-custom-policy に --context-entries で条件キーの値を渡すと、操作を行わずに判定だけを確かめられます。規則の理解には、この記事の評価器で値を変えて試す方法も役立ちます。
まとめ
- Condition は 条件演算子・条件キー・値 の3つで書く
- 演算子どうし・キーどうしは AND、1つのキーの複数の値は OR。否定の演算子の複数の値は「どれにも一致しない」
- リクエストにキーが無いと、肯定の演算子は false、否定の演算子は true、IfExists は true
- Deny で MFA を必須にするなら BoolIfExists と "false"。Allow なら Bool と "true"
- 複数値のキーには ForAllValues / ForAnyValue。ForAllValues を Allow で使うなら Null の "false" を添える
- 条件キーは 「リクエストに含まれるとき」 まで確かめて選ぶ
- 判定は simulate-custom-policy で、操作を行わずに確かめられる
参考・出典
- AWS IAM ユーザーガイド「IAM JSON ポリシー要素:条件演算子(reference_policies_elements_condition_operators)」
- AWS IAM ユーザーガイド「複数のコンテキストキーまたは値による条件(reference_policies_condition-logic-multiple-context-keys-or-values)」
- AWS IAM ユーザーガイド「単一値と複数値のコンテキストキー(reference_policies_condition-single-vs-multi-valued-context-keys)」
- AWS IAM ユーザーガイド「AWS グローバル条件コンテキストキー(reference_policies_condition-keys)」
- AWS CLI Command Reference「iam simulate-custom-policy」
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IAMポリシーConditionの書き方|条件演算子と条件キー一覧」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。