[アップデート] AWS KMS 向けの Interface VPC endpoints がエンドポイントポリシーに対応しました!(おそらく)通算33個目!

一昔前はエンドポイントポリシーを設定できるのはゲートウェイ型だけだったはずなのに立派になったなぁ……。

コンバンハ、千葉(幸)です。

KMS 向けの VPC エンドポイント(インタフェース)がエンドポイントポリシーの設定に対応しました!

より細かいアクセス制御を行うことができるようになりましたね!(でもその分、全体の設計はややこしくなるぞ!)

目次

VPC エンドポイントとは

まずはそもそものところから抑えておきましょう。 VPC エンドポイントとは、 VPC 内部のプライベートな環境から AWS サービスのエンドポイント(グローバルIP)に対するアクセス経路を提供してくれるものです。

パブリックIP や NAT デバイスが不要で、かつ Amazon が管理するネットワークから離れることなくサービスエンドポイントに到達できます。

VPC エンドポイントにはゲートウェイ型インタフェース型の2種類があります。

ゲートウェイ型の場合

ゲートウェイ型を使用する場合は、ルートテーブルのターゲットとして指定する必要があります。

VPC 内のサーバがサービスエンドポイントにアクセスしようとする場合に、宛先のIPはそのままグローバルIPアドレスとなります。ゲートウェイを経由し、Amazon が管理するネットワークを通ってサービスエンドポイントに到達します。

相対的に古いタイプであり、対応している AWS サービスは以下の2種類のみです。

  • Amazon S3
  • DynamoDB

インタフェース型の場合

インタフェース型の場合は、上記のような設定が必要ありません。

VPC 内のサーバがサービスエンドポイントにアクセスしようとした場合、その宛先はインタフェースエンドポイントのプライベートIPとなります。

よって、ルートテーブルに追加が不要なほか、セキュリティグループや NetworkACL でサービスエンドポイント向けのアウトバウンドを考慮する必要がありません。インタフェースエンドポイントから対向の環境に対しては、AWS PrivateLink という機能を用いて通信が行われます。

ややこしいですが、AWS のサービスエンドポイントの他にも、カスタマーが作成するエンドポイントサービスを宛先にすることができます。

対応しているサービスは多数あるので、この次に触れます。

VPC エンドポイントポリシー とは

各エンドポイントにおいて、接続先のサービスへのアクセスを制御するエンドポイントポリシーを設定することができます。分類としては、 S3 に設定するバケットポリシーと同じようにリソースベースのポリシーというものになります。他のポリシーと同じように、JSON形式でステートメントを定義することになります。

エンドポイントポリシーはすべてのサービスでサポートされているわけではありません。一昔前はゲートウェイ型だけで対応していたように記憶していますが、現在ではインタフェース型でも対応しているサービスがそれなりに存在します。

インタフェース型をサポートしているサービスの一覧と、それがエンドポイントポリシーに対応しているかを表現したものが以下の表となります。

インタフェース型をサポートするサービス エンドポイントポリシー対応
Amazon API Gateway
Amazon AppStream 2.0 -
AWS App Mesh -
Application Auto Scaling
Amazon Athena
Amazon Aurora
AWS Auto Scaling
AWS Certificate Manager Private Certificate Authority -
Amazon Cloud Directory -
AWS CloudFormation -
AWS CloudTrail -
Amazon CloudWatch
Amazon CloudWatch Events
Amazon CloudWatch Logs
AWS CodeBuild
AWS CodeCommit
AWS CodePipeline -
AWS Config -
AWS Data Exchange -
AWS DataSync -
AWS Device Farm -
Amazon EC2
EC2 Image Builder
Amazon EC2 Auto Scaling
AWS Elastic Beanstalk
Amazon Elastic File System
Elastic Load Balancing
Amazon Elastic Container Registry
Amazon Elastic Container Service -
Amazon EMR
Amazon Fraud Detector -
AWS Glue -
AWS Key Management Service  New!
Amazon Keyspaces (Apache Cassandra 向け)
Amazon Kinesis Data Firehose
Amazon Kinesis Data Streams
AWS License Manager
Amazon Managed Blockchain -
Amazon Quantum Ledger Database (Amazon QLDB) -
Amazon RDS
Amazon RDS Data API
Amazon Rekognition
Amazon SageMaker および Amazon SageMaker ランタイム
Amazon SageMaker でのノートブック
AWS Secrets Manager
AWS Security Token Service
AWS Server Migration Service -
AWS Service Catalog -
Amazon Simple Email Service (Amazon SES) -
Amazon SNS
Amazon SQS
AWS Step Functions
AWS Systems Manager -
AWS Storage Gateway -
Amazon Transcribe -
Amazon Transcribe Medical -
AWS Transfer for SFTP -
Amazon WorkSpaces -
他の AWS アカウントによってホストされるエンドポイントサービス -
サポートされる AWS Marketplace パートナーサービス -

VPC エンドポイント によるサービスのアクセスコントロール - Amazon Virtual Private Cloud

全部で 60 個ある対応サービスのうち、エンドポイントポリシーをサポートしているのは 33 個です。今回のアップデートによって、AWS Key Management Service が 33 番目としてここに名を連ねることになったということですね。

※現時点のドキュメント(英語版)を拠り所に算出したので、実態と違っていたらごめんなさい。

ドキュメントを確認してみる

KMS における VPC エンドポイントポリシーについては、以下ページに記載があります。

Connecting to AWS KMS through a VPC endpoint - AWS Key Management Service

エンドポイントポリシーの例は2つ載っています。どんな制御を行っているか見てみましょう。

パターン1. 特定のユーザーが特定のキーに対して特定のアクションを可能

ポリシー例は以下です。

{
   "Statement":[
      {
         "Sid": "Allow decrypt and view permission",
         "Principal": {"AWS": "arn:aws:iam::111122223333:user/ExampleUser"},
         "Effect":"Allow",
         "Action": [ 
             "kms:Decrypt",
             "kms:DescribeKey",  
             "kms:ListAliases", 
             "kms:ListKeys"
          ],
         "Resource": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      }
   ]
}

ここではプリンシパル(IAMユーザー)とリソース(CMK/カスタマーマスターキー)、アクションを限定的なものにしています。VPC エンドポイントを経由する際には、特定のユーザーが特定のキーに対して参照系のアクションを実行することだけが許可されているということになります。

IAM ユーザーに適用されているポリシーや CMK に適用されているキーポリシーで許可されていたとしても、VPC エンドポイントを経由する際には指定されたアクション以外は Deny されることになります。

パターン2. 外部アカウントのプリンシパルによるアクションを拒否

ポリシー例は以下です。

{
  "Statement": [
    {
      "Sid": "Access for a specific account",
      "Principal": {"AWS": "*"},
      "Action": "kms:*",
      "Effect": "Deny",
      "Resource": "arn:aws:kms:*:111122223333:key/*",
      "Condition": {
        "StringNotEquals": {
          "aws:PrincipalAccount": "111122223333"
        }
      }
    }
  ]
}

外部アカウントのプリンシパルによるアクションをすべて拒否するような方式になっています。

外部アカウントのプリンシパルによる操作は CloudTrail による記録の対象とならないため、VPC内から KMS アクションを呼び出せるのは自アカウントのプリンシパルに制限する、というケースで説明されています。

(サーバ内に侵入されてクレデンシャルを持ち込まれた場合、などが該当するのでしょうか? CMK のキーポリシーで制限しきれない禁止アクションをここで制限するとか……?ちょっと具体的にイメージがついていないです。)

やってみた

今回やりたいことは以下のイメージです。

VPC 内の EC2 から、特定の CMK に対してのみアクセスがしたいです。

  • EC2 にアタッチしている Test-EC2-Role にはKMSに関する許可を持つポリシーをアタッチしない
    • SSM セッションマネージャーを用いて接続するので AWS 管理ポリシー AmazonSSMManagedInstanceCoreのみをアタッチ
  • カスタマー管理 CMK として以下を用意
    • Test-Key
    • Test-Key2
  • それぞれの CMK のキーポリシーで Test-EC2-Roleキーユーザーとして定義
  • VPC エンドポイントポリシーで Test-Key2 に対するアクションのみ許可
  • 実行するアクションは kms:DescribeKey

カスタマー管理 CMK の準備

Test-Key と Test-Key2 を作成しました。それぞれ「キーユーザー」として Test-EC2-Role を指定しています。

そうすると、キーポリシーの以下ハイライト部が自動で設定されます。

{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::000000000000:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::000000000000:role/Test-EC2-Role"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::000000000000:role/Test-EC2-Role"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}

今回実行したい kms:DescribeKey がキーポリシーで許可されているので、IAMロール側で IAM ポリシーを追加する必要はありません。

AWS KMS リソースへのアクセスの管理の概要 - AWS Key Management Service

VPC エンドポイントポリシーを設定しないで試してみる

まず VPC エンドポイントポリシーで制限しない場合にどういう挙動になるかを確認しておきます。サービス名 com.amazonaws.ap-northeast-1.kms を、ポリシーを フルアクセス にして作成しました。

EC2 に SSM セッションマネージャーで接続し、東京リージョンの KMS のサービスエンドポイント kms.ap-northeast-1.amazonaws.com を名前解決してみます。インタフェースエンドポイントが持つプライベートIPが引けました。

sh-4.2$ nslookup kms.ap-northeast-1.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   kms.ap-northeast-1.amazonaws.com
Address: 192.168.3.204
Name:   kms.ap-northeast-1.amazonaws.com
Address: 192.168.1.23

この状態であれば、 KMS に対して API を実行する際にはインタフェースエンドポイントを経由することになります。

Test-Key に対して aws kms describe-key を実行します。問題なく結果が返ってきました。

h-4.2$ aws kms describe-key --key-id alias/Test-Key --region ap-northeast-1
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "6d106236-7f6d-4290-b6ff-1xxxxxe6dd6f",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ],
        "Enabled": true,
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1594828861.811,
        "Arn": "arn:aws:kms:ap-northeast-1:000000000000:key/6d106236-7f6d-4290-b6ff-1xxxxxe6dd6f",
        "AWSAccountId": "000000000000"
    }
}

Test-Key2 に対して実行します。こちらも問題なく結果が返ってきました。

sh-4.2$ aws kms describe-key --key-id alias/Test-Key2 --region ap-northeast-1
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "cb7743a8-e066-4bde-95e0-5xxxxxfb1d15",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ],
        "Enabled": true,
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1594872075.999,
        "Arn": "arn:aws:kms:ap-northeast-1:000000000000:key/cb7743a8-e066-4bde-95e0-5xxxxxfb1d15",
        "AWSAccountId": "000000000000"
    }
}

IAM ポリシーと CMK キーポリシーの設定は問題ないことが確認できました。いぇーい。

VPC エンドポイントポリシーを設定してやってみる

エンドポイントポリシーを設定してみます。

今回は以下のようなポリシーを設定しました。

{
   "Statement":[
      {
         "Sid": "Allow decrypt and view permission",
         "Principal": {"AWS": "*"},
         "Effect":"Allow",
         "Action": [ 
             "kms:Decrypt",
             "kms:DescribeKey",  
             "kms:ListAliases", 
             "kms:ListKeys"
          ],
         "Resource": "arn:aws:kms:ap-northeast-1:000000000000:key/cb7743a8-e066-4bde-95e0-5xxxxxfb1d15"
      }
   ]
}

リソースとして Test-Key2 の ARN のみを指定しています。Test-Key に対するアクセスを明示的に Deny していないものの、いわゆる暗黙的な Deny により拒否されることを期待します。

エンドポイントポリシーを設定したのち、再度 Test-Key に対してコマンドを実行します。アクセスが拒否されたことが確認できました。

h-4.2$ aws kms describe-key --key-id alias/Test-Key --region ap-northeast-1

An error occurred (AccessDeniedException) when calling the DescribeKey operation: User: arn:aws:sts::000000000000:assumed-role/Test-EC2-Role/i-038a7b0885cbdc78e is not authorized to perform: kms:DescribeKey on resource: arn:aws:kms:ap-northeast-1:000000000000:key/6d106236-7f6d-4290-b6ff-1xxxxxe6dd6f

Test-Key2 に関しては変わらず実行できました。想定どおりです。

sh-4.2$ aws kms describe-key --key-id alias/Test-Key2 --region ap-northeast-1
{
    "KeyMetadata": {
        "Origin": "AWS_KMS",
        "KeyId": "cb7743a8-e066-4bde-95e0-5xxxxxfb1d15",
        "Description": "",
        "KeyManager": "CUSTOMER",
        "EncryptionAlgorithms": [
            "SYMMETRIC_DEFAULT"
        ],
        "Enabled": true,
        "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1594872075.999,
        "Arn": "arn:aws:kms:ap-northeast-1:000000000000:key/cb7743a8-e066-4bde-95e0-5xxxxxfb1d15",
        "AWSAccountId": "000000000000"
    }
}

IAM ロールに AdministratorAccess をアタッチしたら?

「暗黙的な Deny と 明示的な Allow が戦ったら Allow が勝つ」みたいなやつ無かったっけ?というぼんやりとした記憶から、IAM ロールに AWS 管理ポリシーの AdministratorAccess をアタッチしてみました。

AdministratorAccess であれば当然 Test-key に対するアクセス権も持っています。 CMK のキーポリシーでは以下のステートメントが定義されていることから、VPC エンドポイントポリシーを考慮しなければ問題なくアクセスできる状態です。

{
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::000000000000:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },

結果としては、 Test-key に対する aws kms describe-key は変わらず拒否されました

ポリシーの評価論理は見るたびに頭が痛くなるのですが、 VPC エンドポイントポリシーはそれ単体で考えた方が理解しやすそうです。まさにゲートウェイのように、「リソースにたどり着く以前にそこを通れるかどうか」の評価が前段で行われている……というように自分に理解させました。

ポリシーの評価論理 - AWS Identity and Access Management

おわりに

AWS KMS 向けのインタフェースエンドポイントでエンドポイントポリシーが設定できるようになったことを確認しました。

より細かで柔軟な制御ができるようになった一方で、IAM ポリシー、キーポリシー、エンドポイントポリシーと考慮すべきポイントが分散されるため、きちんと方針を決めて設計しないと辛くなりそうです。

高いセキュリティレベルが求められる環境ではすべて最小に絞っていくということになるかと思います。一方で必ずしもそうでない環境においては、セキュリティリスクを鑑みてどこか一か所に制御を寄せ、他は緩めておく、という方針が現実的なのかなという感触を持っています。

正解がない部分なので、精一杯頭を抱えていきたいですね。

以上、千葉(幸)がお送りしました。

おまけに

インタフェースエンドポイントがエンドポイントポリシーに対応したのっていつっだっけ?が気になり過ぎたので調べると、ドキュメント上では 2019 年 3 月にアップデートがかかっていました。

https://github.com/awsdocs/amazon-vpc-user-guide/commit/8cd6b218af2908c6b88310c3fce514894f3e6243#diff-4684654c729bb7f58006c347a600a701

- + Interface endpoints do not support the use of endpoint policies\. Full access to the service through the interface endpoint is allowed\.
+ + Interface endpoints support the use of policies for services that support endpoint policies\. For information about the services that support policies, see [Controlling Access to Services with VPC Endpoints](vpc-endpoints-access.md)\.

スッキリしました。