AWS ポリシーの Condition、単一値と複数値の違いを理解して正しく書こう!
はじめに
こんばんは、菅野です。
IAM ポリシーや S3 バケットポリシーの condition 句で条件を書いて制限するというのはよく使う機能ですが、condition 句の条件キーの値タイプには「単一値」と「複数値」の2種類があり、値タイプの種類によって書き方を変える必要があります。
皆さんはこの違いを意識して使っていますか?
今回はその点について AWS のドキュメントのどこに書いてあるのかという情報とともに紹介します。
条件キー(コンテキストキー)について
例えばアクセス元の IP アドレスで制限するためのグローバル条件コンテキストキー(長いので今後は「条件キー」と呼びます)「aws:SourceIp」をよく使ってるブログ記事などをよく見かけます。皆さんも一度は使ったことがあるかと思います。
では条件キーは他にどんなものがあるのか?という疑問を持った方は以下のドキュメントをブックマークしておきましょう。条件キーが一覧になって記載されています。
AWS global condition context keys
このページには各条件キーの値タイプ(Value type)が書かれてて、ここに書かれている「単一値(Single-valued)」と「複数値(Multivalued)」が今回注目していただきたい部分となります。
この条件キーは「単一値」なのか「複数値」なのか?
どうやって見分けるかですが、一番簡単なのは「先ほどのドキュメントで調べる」です。覚える必要はありません。
では何が違うのかですが、リクエストコンテキストに必ず一つの値だけが渡されるものは「単一値」、複数の値が渡される可能性があるものは「複数値」になります。
これについては AWS のドキュメントに具体例が書かれています。
Single-valued vs. multivalued context keys
このページに書かれていることをざっくり書くとこんな感じになります。
- aws:ResourceTag/tag-key
- 単一値
- 一つのタグは一つの値しか持てないので、「tag-key」を指定しているこの条件キーは必ず一つの値だけが渡される
- aws:TagKeys
- 複数値
- 一つのリソースは複数のタグを持てるので、タグのキー名として複数の値が渡される可能性がある
条件ポリシーの書き方の違い
ここが本題です。
複数の条件のどれかが当てはまれば、という場合の書き方に違いがあります。
こちらも AWS のドキュメントに具体例が書かれています。
上記ページに書かれている内容の説明として、まずは単一値の場合を先ほどの「aws:ResourceTag/tag-key」を例に condition 句を書いてみます。
タグの environment キーの値が「stg」もしくは「dev」だったらという「or条件」になり、条件演算子は「StringEquals」となります。
"Condition": {
"StringEquals": {
"aws:RequestTag/environment": [
"stg",
"dev"
]
}
}
では次に複数値の場合を、先ほどの「aws:TagKeys」を例に書いてみます。
ユーザーがリクエストする際に、対象リソースのタグとして「environment」もしくは「project」のどちらかが指定されていれば、という「or条件」となり、条件演算子は「ForAnyValue:StringEquals」と、「StringEquals」の前に「ForAnyValue:」がついているのが単一値の条件キーとの違いとなります。
"Condition": {
"ForAnyValue:StringEquals": {
"aws:TagKeys": [
"environment",
"project"
]
}
}
「environment」と「project」の「and条件」にしたい場合は「ForAllValues:StringEquals」を使います。
また、完全一致(StringEquals)ではなく部分一致(StringLike)を使う場合も、複数値の条件キーの場合は同様に「ForAnyValue:StringLike」や「ForAllValues:StringLike」のように書く必要があります。
まとめ
ネット上には参考になるブログ記事が数多くあり、そこに書かれている通りに書けばほぼ間違いなく動きます。
ですがその内容をコピーして条件キーと値だけを変えて使ってしまい、複数値の条件キーなのに「ForAnyValue:」を付けなかった、というのはありそうな話です。
一見正しく動いているように見えて「書き方が間違っているために正しい判定が行われていない」ということが無いように以下を意識していきましょう。
- 条件キーには 単一値と複数値があることを意識する
- AWSのドキュメントで条件キーを調べる習慣をつける
- 「ForAnyValue:」や「ForAllValues:」を使う必要があるのか確認する
おまけ
「aws:CalledVia」はリクエストを実行したサービスなんだから単一値だと思ったのですが実は複数値なんです。
なんでだろうとAWS global condition context keysを読んでみると、いくつかの AWS サービスが関わっていることがあって、それら全てのサービスが順番通りにリクエストコンテキストに書かれて渡されるから「複数値」なんだそうです。
ちなみに最初のサービスを指定する「aws:CalledViaFirst」と、最後のサービスを指定する「aws:CalledViaLast」はどちらも「単一値」です。
確かに最初と最後なんだから一つの値しかあり得ませんよね!