はじめに
私の組織では、リソース管理を徹底するために、2タグ(用途や作成者など)を必須としています。
対象ユーザーにはIAMポリシーをアタッチし、タグ未設定の場合はリソース作成を拒否するようにしています。
しかし、IAMポリシーの書き方によっては、タグ必須にしたはずなのにリソースを作成できてしまうことがあります。本記事では、その落とし穴を整理します。
本記事の方法は、EC2 / EFS / VPC のリソース作成時に、タグ未設定の場合はリソース作成を拒否する制御として適用可能です。
今回のタグ運用は、コスト配分タグによるコスト管理が目的ではありません。
誰が・何のために作成したリソースなのかを把握し、管理・棚卸を行うためにタグ付与を必須化しています。
こんなことで困っていませんか?
- オーナー不明リソースが増えている
- タグ必須のIAMポリシーを設定したのに、制御が効かない
- Cost Explorerでタグ別にコスト可視化・管理したい
今回のポイント
今回の私がはまった落とし穴は、Null条件に複数のタグを指定するとAND条件として評価されることでした。
2タグを両方必須にしたい場合は、タグごとにDeny Statementを分ける必要があります。
❌ 1つのDeny Statementで、2タグをまとめて必須化する
一見問題なさそうですが、落とし穴があります。
ここでは説明を分かりやすくするため、必須化したいタグを Tag1 と Tag2 として記載しています。実際には、任意のタグ名に置き換えてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRunInstancesWithout<Tag1>And<Tag2>",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"Null": {
"aws:RequestTag/Tag1": "true",
"aws:RequestTag/Tag2": "true"
}
}
}
]
}
Null条件とは
IAMポリシーのNull条件演算子は、指定したキーが存在しないかどうかを判定します。
例えば、Tag1が存在しない場合は、以下のように表します。
"aws:RequestTag/Tag1": "true"
なぜ期待通りに動かないのか?
ポイントは、IAMのCondition評価ルールです。
今回のIAMポリシーでは、
"Condition": {
"Null": {
"aws:RequestTag/Tag1": "true",
"aws:RequestTag/Tag2": "true"
}
}
としています。
IAMでは、同じCondition演算子(今回でいうNull)の中で複数キーを指定するとAND条件として評価されます。
そのため、今回のポリシーでは
Tag1が無い
かつ
Tag2が無い
と判定されます。
つまり、両方のタグが存在しない場合のみDenyが発動します。
一方で、どちらか一方のタグが設定されている場合はNull条件全体の判定がFalseとなるため、Denyは発動せず、リソースを作成できてしまいます。
評価結果(NGパターン)
| タグ状態 | Tag1 Null判定 | Tag2 Null判定 | Null判定全体 | リソース作成可否 |
|---|---|---|---|---|
| 両方あり | False | False | False | ✅ Allow(作成可能) |
| 片方だけ | False | True | False | ✅ Allow(意図せず作成されてしまう) |
| 両方なし | True | True | True | ❌ Deny(作成不可) |
✅ タグごとにDeny Statementを分けて必須化する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRunInstancesWithout<Tag1>",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"Null": {
"aws:RequestTag/Tag1": "true"
}
}
},
{
"Sid": "DenyRunInstancesWithout<Tag2>",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"Null": {
"aws:RequestTag/Tag2": "true"
}
}
}
]
}
なぜ期待通りに動くのか?
今回のIAMポリシーでは、Tag1用とTag2用でDeny Statementを分けています。
{
"Statement": [
{
"Condition": {
"Null": {
"aws:RequestTag/Tag1": "true"
}
}
},
{
"Condition": {
"Null": {
"aws:RequestTag/Tag2": "true"
}
}
}
]
}
IAMでは、複数のDeny Statementがある場合、どれか1つでも条件に一致すると明示的なDenyとなり、操作は拒否されます。
そのため、今回のポリシーでは
Tag1が無い
または
Tag2が無い
の場合にDenyが発動します。
結果として、Tag1とTag2の両方が設定されている場合のみ、リソースを作成できます。
評価結果(OKパターン)
| タグ状態 | Tag1 Null判定 | Tag2 Null判定 | Deny発動有無 | リソース作成可否 |
|---|---|---|---|---|
| 両方ある | False | False | 無 | ✅ Allow(作成可能) |
| 片方だけ | False | True | 有 | ❌ Deny(作成不可) |
| 両方ない | True | True | 有 | ❌ Deny(作成不可) |
最後に
私自身まだ勉強中ですが、本記事が同じような課題に悩んでいる方の参考になれば幸いです。
現在、組織で利用するAWSリソースについて、利用されていないリソースに対する無駄なコストの発生を防ぐための管理・運用の仕組みづくりを取り組んでいます。
今後も、実際に取り組んだ内容や学んだことを発信していきたいと思います!