[小ネタ] AWS IAMポリシーの Conditionで使える条件演算子 “Null” の使いみちを考える

がっ
2021.03.01

はじめに

IAMポリシーの Condition で使える条件演算子 Null の使いみちを自分なりに考えてみました。

前提知識

IAMポリシーの Condition

IAMポリシーの Condition要素 でポリシーが実行される条件を指定します。

例えば以下は 「 (EC2)リソースの Protectionタグの値が "enabled" である場合 に そのリソースの削除(Delete*)を禁止(Deny)する」 ステートメントです。

"Effect": "Deny",
"Action": "ec2:Delete*",
"Resource": "arn:aws:ec2:*",
"Condition" : {
  "StringEquals" : {
    "aws:ResourceTag/Protection": "enabled"
  }
}

一番シンプルな Conditionは以下のような構文です。

"Condition" : {
  "(条件演算子)" : {
    "(条件キー)" : "(条件キーの値)"
  }
}

条件演算子 を使用して 条件キーの値と、 リクエストコンテキスト(リクエストに関する情報) の値との比較を行います。 代表的な条件演算子として 文字列の完全一致比較に使う StringEquals や 数値の大小比較に使う NumericLessThan/NumericGreaterThan があります。

条件キーで「何の情報と比較を行うのか」を指定します。 条件キーには サービス関係なく利用できる グローバル条件キー と、 AWSサービス固有の条件キーの 2種類あります。

例えば aws:username はグローバル条件キーで、プリンシパルのユーザー名を示しています。 ec2:Vpc はサービス固有の条件キーで、対象リソース(インスタンスやセキュリティグループ)のVPC ARNを示しています。

Null条件演算子とは

Null条件演算子 は指定した条件キーがリクエストコンテキスト(リクエストに関する情報) に 含まれているかをチェックするために使います。

Null を使うときの条件キーの値は true(キーは含まれない) もしくは false(キーは含まれる) です

Null の使いみち

特定の条件キーの有無で Allow/Deny したいときに使う

以下ステートメントは "一時的な認証情報 を利用した EC2 APIは許可されない" ことを表しています。

{
  "Version": "2012-10-17",
  "Statement":{
      "Action":"ec2:*",
      "Effect":"Allow",
      "Resource":"*",
      "Condition":{"Null":{"aws:TokenIssueTime":"true"}}
  }
}

AWSドキュメントの 条件キーの有無をチェックする条件演算子 にある例を引用します。

ユーザーが一時的な認証情報を利用するとき のみ 、リクエストコンテキストには aws:TokenIssueTime が含まれます。 これを利用して「一時的な認証情報を使わないときのみ、 EC2 APIを許可する」ステートメントを書いています。

※ Null と true/false の組み合わせ、よく混乱することあります。以下覚えておくと良いでしょう。

  • 条件キーが 有るとき の Allow/Deny を示したいときは "Null":{"条件キー": "false"} を使う
  • 条件キーが 無いとき の Allow/Deny を示したいときは "Null":{"条件キー": "true"} を使う

「特定の条件キーがある前提」であることを示すために使う

以下 "Protection=Enabled のタグが付いた EC2リソースを削除できないようにする" ポリシー例です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Resource": "arn:aws:ec2:*",
      "Action": [
        "ec2:Delete*",
        "ec2:Terminate*"
      ],
      "Condition": {
        "Null": {
          "aws:ResourceTag/Protection": false
        },
        "StringEquals": {
          "aws:ResourceTag/Protection": "enabled"
        }
      }
    }
  ]
}

※以下記事からの引用、AWS Organizations のサービスコントロールポリシー(SCP)。

このポリシーの Condition 部分で言いたいことは以下 2つです

  • 「Protectionタグが存在する」前提で、
  • 「Protectionタグの値が "enabled" である」

前者を Null条件演算子を使って書いています。

小ネタ(言いたいこと)

実は 上で示した例(SCP)は Null部分が有っても無くても 同じ挙動をします。

img

両者のケースごとの評価は以下のとおりです。

Null有り Ver. Null無し Ver.
Protectionタグが無いとき このポリシーは無視 ※ このポリシーは無視 ※
Protectionタグが有り、"enabled" である ポリシー実行(明示的にDeny) ポリシー実行(明示的にDeny)
Protectionタグが有り、"enabled" 以外である このポリシーは無視 このポリシーは無視

太字で書いた、最終的な結果( Protectionタグが無いとき、このポリシーは無視 )は一緒ですが、 どのような過程で無視されるかが異なります。

まとめると以下のような感じです。

img

▼ Null有り Ver.

該当キー( aws:ResourceTag/Protection )が無いときに、 Null部分は False となります。 Condition の True/False は 全条件のAND(論理積) で評価されるためこの時点で Condition 部分が False となることが確定します。

▼ Null無し Ver.

該当キー( aws:ResourceTag/Protection )が無いため、 StringEquals部分の 評価ができません 。 よって、このポリシーは 評価に失敗 します。

→ つまり … 後味が悪い(主観)

おわりに

今回伝えたかったことは以下です。

  • 条件キーには可用性があること
  • 条件キーが無いとき、評価に失敗する可能性があること
  • 真面目に 「条件キーがある前提」を示すために Null条件演算子を活用できること

「"Null有り Ver." でも Condition評価の順番によっては 同じ結末 (評価に失敗) になり得る」という意見は、その通りです。

また、似た条件演算子に IfExists があります。 今回の記事と合わせて見てみると良いかもしれません。

参考