![[アップデート] AWS KMS 向けの Interface VPC endpoints がエンドポイントポリシーに対応しました!(おそらく)通算33個目!](https://devio2023-media.developers.io/wp-content/uploads/2019/05/aws-kms.png)
[アップデート] AWS KMS 向けの Interface VPC endpoints がエンドポイントポリシーに対応しました!(おそらく)通算33個目!
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンバンハ、千葉(幸)です。
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のみをアタッチ
 
- SSM セッションマネージャーを用いて接続するので AWS 管理ポリシー 
- カスタマー管理 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 月にアップデートがかかっていました。

- + 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)\.
スッキリしました。












