暗号化されたEBSボリュームを作成できずハマった話

暗号化されたEBSボリュームを作成できずハマった話

Clock Icon2020.02.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。AWS 事業本部の中川です。

暗号化された EBS ボリュームを作成できない事象に遭遇しました。
権限を絞りすぎたことで、リソース作成時に権限不足である旨のエラーが表示され失敗するケースはよくあるかと思います。
しかし、今回遭遇した事象は、作成時にエラーは表示されていないのにリソースが作成されないというもので、特殊なケースでした。
エラーが表示されず原因特定にハマったので、備忘録として残します。

前提

以下のようなポリシーが付与された IAM ユーザーを使用しています。(実際には ReadOnlyAccess のポリシーが付与されていたり、他に Condition があります。)

{
    "Version": "2012-10-17",
    "Statement":[
        {
            "Effect": "Allow",
            "Action":[
                "ec2:CreateVolume"
           ],
            "Resource":[
                "arn:aws:ec2:*:*:volume/*"
            ]
        },
        {
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp":[
                        "x.x.x.x"
                   ]
                }
            }
        }
   ]
}

事象

暗号化のチェックボックスを有効にして、カスタマーマスターキー(以下 CMK)はデフォルトを選択し、ボリュームを作成します。

「ボリュームは正常に作成されました」と表示され、EBS ボリュームが作成されたように見えます。ボリューム ID をクリックして、一覧の画面に戻ります。

しかし、一覧でボリューム ID と一致するボリュームが表示されません。右上の更新ボタンをクリックしても表示されず、ボリュームは作成されていないことがわかります。

原因

aws:SourceIp で接続 IP アドレスの制限をしながら、EBS の暗号化(EBS から KMS の呼び出し)をしていたことが原因でした。

aws:SourceIpのドキュメントを見ると以下の記述があります。

aws:SourceIp 条件キーをポリシーで使用して、プリンシパルが指定された IP 範囲内からのみリクエストを行うことを許可できます。ただし、このポリシーは、ユーザーに代わって呼び出しを行う AWS のサービスへのアクセスを拒否します。たとえば、AWS CloudFormation がサービスロールを使用して Amazon EC2 を呼び出してインスタンスを停止するとします。この場合、ターゲットサービス (Amazon EC2) が呼び出し元のサービス (AWS CloudFormation) の IP アドレスを認識するため、リクエストは拒否されます。

aws:SourceIp は、「ユーザーに代わって呼び出しを行うAWSサービスへのアクセスを拒否する」ことが仕様のようです。
EBS ボリュームの暗号化では、EBS が KMS にリクエストを送信して、暗号化で使用するを CMK を指定しています。
つまり、EBS の暗号化で KMS を呼び出すリクエストは、aws:SourceIp によって拒否されていたことがわかりました。

回避策

本事象の回避策は 2 つあります。

  1. aws:SourceIp を一時的に使用しないようにする(または条件から除いてしまう)
  2. kms:ViaServiceを使用して、CMKを呼び出していないときを条件として追加する

2.は呼び出される AWS サービスが KMS の場合でのみ有効な回避策です。2.を使う場合、前提のポリシーを以下のように変更します。

{
    "Version": "2012-10-17",
    "Statement":[
        {
            "Effect": "Allow",
            "Action":[
                "ec2:CreateVolume"
          ],
            "Resource":[
                "arn:aws:ec2:*:*:volume/*"
            ]
        },
        {
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "Null": {
                    "kms:ViaService": "true"
                },
                "NotIpAddress": {
                    "aws:SourceIp":[
                        "x.x.x.x"
                  ]
                }
            }
        }
  ]
}

kms:ViaService は、CMK の使用を指定の AWS サービスからのリクエストに制限する条件キーです。
Null は、条件キーの存在を確認する条件演算子です。Null で{"kms:ViaService": "true"}と指定すると、「kms:ViaService が存在しない(≒CMK を呼び出していない)」という条件になります。
これを接続元 IP アドレスを制限する条件に追加することで、「CMK を呼び出していないかつ接続元 IP を制限する」という条件になります。

さいごに

aws:SourceIp で接続元 IP アドレスを制限すると、ユーザーに代わって呼び出しを行う AWS のサービスへのアクセスは拒否されることがわかりました。
KMS 以外のサービスを呼び出す際は、aws:SourceIp を条件から外さなくてはならないので、接続元 IP を制限をする際には気をつける必要があると思いました。

この記事がどなたかのお役に立てたら幸いです。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.