aws:RequestTagの仕様を誤解していた
概要
ドキュメントをちゃんと読んでいればこのような誤解はしないのかもしれませんが、ざっとしか確認しなかったために以下のようにaws:RequestTagを条件に指定したポリシーが想定通りの挙動をせず悩んでました。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "ec2:CreateTags",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringEquals": {
"aws:RequestTag/environment": [
"preprod",
"production"
]
},
}
}
}
当初の認識
誤解していたのはドキュメント中の次の部分です。
リクエストで渡すことができるタグを制御します。これを行うには、aws:RequestTag/key-name 条件キーを使用して、AWS リソースのタグ付けを行うリクエストで渡すことができるタグキーバリューのペアを指定します。
後半の「リクエストで渡すことができるタグキーバリューのペアを指定」を正しく理解できておらず、
- リクエストではIAMユーザーにアタッチされているタグのキーバリューが渡される
- 上記のポリシーの場合、
environment: preprod or productionが設定されたIAMユーザーにのみCreateTagsを許可する
というような理解をしていました。
そのため、CreateTagを実行するIAMユーザーに対しenvironment: productionというタグをアタッチし、

※画像に誤りがあります。environment:dev -> environment:productionで確認しています
既存のEC2インスタンスにOwner: testという新しいタグを追加しようとしてエラーが発生し、なぜエラーになるのかわからないという事態が起こりました。

※本来はこのようにIAMユーザーのタグと比較したい場合、aws:RequestTagではなくaws:PrincipalTagを使用します。
正しい認識
aws:RequestTagの正しい挙動は以下です。
-
aws:RequestTagではCreateTagで作成するタグのキーバリューを参照できる - 上記のポリシーの場合、
CreateTagで作成するタグをキーがenvironmentで値がpreprod or productionのみに制限する
上記の通りaws:RequestTagはIAMユーザーにアタッチされたタグによりCreateTagアクションを制限するものではなく、CreateTagアクションで作成するタグを制限するための条件キーです。
今回のポリシーではIAMユーザーにアタッチされているタグは関係なく、CreateTagでenvironment: preprod or productionのタグのみ作成できます。

またこのように作成するタグを制限する際のベストプラクティスとして、以下のような条件を追加します。
"ForAllValues:StringEquals": {"aws:TagKeys": "environment"}
IAMのCondition要素では、条件キーで大文字・小文字は区別されません。条件値で大文字・小文字が区別されるかどうかは使用する条件演算子によります。
aws:RequestTagではキー名を条件キーに指定するので大文字小文字が区別されません。
その結果aws:RequestTag/environmentではタグキーとしてenvironment Environmentの2種類を受け付けます。
aws:TagKeysは条件値に指定したタグキーとリクエスト内に含まれるタグキーを比較します。
またStringEqualsは条件値の大文字・小文字を区別します。
参考:IAM JSON ポリシー要素: 条件演算子
この条件を追加することにより、タグキーに指定できるキー名をenvironmentのみに制限することができます。
Discussion