概要
プライベートサブネットに置いたEC2インスタンスから、KMSで暗号化・復号を行いたい。しかしKMSはVPCの中にあるサービスではなく、kms.ap-northeast-1.amazonaws.com というパブリックなエンドポイントを持つリージョンサービスです。何も手当てをしなければ、プライベートサブネットからはこのエンドポイントに到達できません。
素直な解決策としてNATゲートウェイを置く方法がありますが、これは「インターネットへの出口を作る」ことでもあります。KMSにアクセスしたいだけなのに、インスタンスからインターネット全体へ通信できる経路ができてしまい、しかもNATゲートウェイは時間課金とデータ処理料金がかかります。
インターフェイスVPCエンドポイント(AWS PrivateLink)を使うと、KMSへの通信をAWSのネットワーク内で完結させられます。インターネットを経由せず、経路も特定のサービスだけに限定できます。さらにKMSのキーポリシーで「このVPCエンドポイント経由でなければ使わせない」という条件まで書けます。
この記事では、インターネットゲートウェイもNATも持たないVPCを舞台に、KMSエンドポイントが無い状態では通信が失敗することを確認したうえで、エンドポイントを作って疎通させ、最後にキーポリシーで経路を強制します。

クラウドおさるKMS は VPC の外にパブリックなエンドポイントを持つリージョンサービスなので、出口の無いプライベートサブネットからは届かぬのでござる。この記事では、エンドポイントが無いと失敗し、作ると通り、キーポリシーで経路まで縛れるところを、弊猿と一緒に順に確かめるでござるな。
この記事のメリット
- ゲートウェイ型とインターフェイス型のVPCエンドポイントの違いを説明できるようになる
- KMSへのアクセス経路として、NATゲートウェイとVPCエンドポイントのどちらを選ぶか判断できるようになる
- プライベートDNSが有効なエンドポイントで、アプリケーションを変更せずに経路だけ差し替えられることを理解できる
- キーポリシーの
aws:sourceVpce条件で、KMSキーの利用経路を強制できるようになる - SCS試験で「プライベートサブネットからAWSサービスへ安全にアクセスする方法」を問う設問に正確に答えられるようになる
執筆者とキャラクター紹介
執筆者:土肥(とひ)
株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。


クラウドおさる



はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。



基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。



猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。
技術解説
VPCエンドポイントの2つの型
VPCエンドポイントには型が2つあり、KMSで使うのはインターフェイス型です。
| 型 | 実体 | 対応サービス | 料金 |
|---|---|---|---|
| ゲートウェイ型 | ルートテーブルに追加されるターゲット | S3、DynamoDB のみ | 無料 |
| インターフェイス型(PrivateLink) | サブネット内に作られるENI(プライベートIP) | KMS、Systems Manager、Secrets Manager など多数 | エンドポイント1つあたりの時間課金 + データ処理料金 |
インターフェイス型は「サブネットの中にそのサービス専用の入り口(ENI)ができる」と考えると理解しやすくなります。通信はそのENI宛てに行われ、AWSのネットワーク内でサービスに転送されます。


プライベートDNSがアプリを変えずに済ませる
インターフェイスエンドポイントを作るとき「プライベートDNS名を有効にする」を選ぶと、VPC内での kms.ap-northeast-1.amazonaws.com の名前解決が、エンドポイントのプライベートIPに変わります。
これが重要なのは、アプリケーションやAWS CLIの設定を一切変更しなくてよいという点です。コードはこれまでどおり通常のエンドポイント名で呼び出し、名前解決の結果だけが変わります。
プライベートDNSを使うには、VPCの enableDnsSupport と enableDnsHostnames が両方とも有効である必要があります。
NATゲートウェイと比べたときの利点
| 観点 | NATゲートウェイ | インターフェイスVPCエンドポイント |
|---|---|---|
| 通信経路 | インターネットを経由する | AWSネットワーク内で完結する |
| 到達範囲 | インターネット全体に出られる | そのサービスにだけ到達する |
| 料金 | 時間課金 + データ処理料金(比較的高い) | 時間課金 + データ処理料金(NATより低い) |
| 監査 | 経路の制御はルートテーブル・SG頼み | エンドポイントポリシーで許可するAPIやリソースを絞れる |
「インターネットに出さずに特定のサービスだけ使わせたい」という要件では、VPCエンドポイントが答えになります。設問に「コスト効率よく」「インターネットを経由せずに」といった条件が付いている場合はほぼこれです。



NAT ゲートウェイはインターネット全体への出口になるが、インターフェイスエンドポイントはそのサービスにだけ届く入り口でござる。猿山でたとえるなら、隣のバナナ倉庫へ行くだけのために山門を開け放つか、倉庫直通の通路を 1 本掘るかの違いでござるな。「インターネットを経由せずに」と言われたら、こちらを思い出すのでござる。
エンドポイントポリシーとキーポリシー
経路を絞る仕組みは2段あります。混同しやすいので整理します。
| 仕組み | 書く場所 | 効き方 |
|---|---|---|
| エンドポイントポリシー | VPCエンドポイント | そのエンドポイントを通るリクエストに対して、許可するAPIやリソースを制限する |
| キーポリシーの条件 | KMSキー | そのキーへのリクエストに対して、どの経路から来たかで許可・拒否する |
キーポリシー側で経路を強制するときは、aws:sourceVpce(エンドポイントID)または aws:sourceVpc(VPC ID)の条件キーを使います。
{
"Sid": "Restrict usage to my VPC endpoint",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-1234abcdf5678c90a"
}
}
}このポリシーには副作用があります。指定したエンドポイント以外からのリクエストがすべて拒否されるため、マネジメントコンソールからの操作や、ユーザーに代わってKMSを呼び出す他のAWSサービス(S3のSSE-KMSなど)からのリクエストも失敗します。本番のキーに適用する場合は、統合サービスからの経路を別のステートメントで許可しておく必要があります。
もう1点、VPCエンドポイント経由のリクエストでは aws:sourceIP 条件キーが効きません。送信元IPで絞っているつもりが素通りになるため、経路を絞るなら必ず aws:sourceVpce か aws:sourceVpc を使います。
実践
インターネットゲートウェイもNATも持たないVPCで、KMSへのアクセスがエンドポイントの有無でどう変わるかを確認します。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| VPC | kms-vpce-lab-vpc | 検証用VPC(CIDR: 10.20.0.0/16。IGW・NATなし) |
| プライベートサブネット | kms-vpce-lab-private-subnet | EC2とエンドポイントを配置(CIDR: 10.20.1.0/24) |
| セキュリティグループ | kms-vpce-lab-endpoint-sg | エンドポイント用(VPC内からのHTTPSを許可) |
| セキュリティグループ | kms-vpce-lab-instance-sg | EC2用(インバウンドなし) |
| VPCエンドポイント | ssm / ssmmessages / ec2messages | Session Managerで接続するため |
| EC2インスタンス | kms-vpce-lab-instance | 疎通確認用。SSMとKMSの権限を持つロールを付与済み |
[!NOTE] 前提環境のTerraform資材は assets/54_q91_kms-vpc-endpoint-private-access にあります。インターフェイスエンドポイントは1つあたり時間課金が発生するため、検証後は削除してください。
このハンズオンで作成するリソースは以下のとおりです。
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| VPCエンドポイント | com.amazonaws.ap-northeast-1.kms | KMSへのプライベート経路 |
| KMSカスタマー管理キー | vpce-lab-key | 経路の強制を確認するためのキー |
手順1: エンドポイントが無い状態で疎通を確認する
AWSマネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。
上部の検索バーに EC2 と入力し、表示された「EC2」を選択します。左側ナビゲーションの「インスタンス」→「インスタンス」を選択し、kms-vpce-lab-instance を選択して「接続」をクリックします。
「接続方法を選択」で「最大限のセキュリティ」(SSM セッションマネージャー)のカードを選び、「接続」をクリックします。ブラウザ上にターミナルが開きます。


ターミナルで次のコマンドを実行します。タイムアウトとリトライ回数を指定して、待たされずに失敗を確認します。
AWS_MAX_ATTEMPTS=1 aws kms list-keys --region ap-northeast-1 \
--cli-connect-timeout 5 --cli-read-timeout 5[!NOTE]
--cli-connect-timeoutだけでは、接続に失敗するたびにAWS CLIがリトライするため結局待たされます。AWS_MAX_ATTEMPTS=1を付けて1回で諦めさせます。
接続がタイムアウトして失敗することを確認します。このVPCにはインターネットへの出口が無く、KMSのパブリックエンドポイントに到達できないためです。


手順2: KMS用のインターフェイスエンドポイントを作成する
上部の検索バーに VPC と入力し、表示された「VPC」を選択します。
左側ナビゲーションの「エンドポイント」を選択し、「エンドポイントを作成」をクリックします。
以下を設定します。
- 名前タグ:
kms-vpce-lab-kms - タイプ:
AWS のサービス - サービス: 検索ボックスに
kmsと入力し、com.amazonaws.ap-northeast-1.kmsを選択(kms-fipsではない方) - VPC:
kms-vpce-lab-vpc - 「プライベート DNS 名を有効化」: 既定でチェックが入っています。入っていることを確認します
- サブネット: アベイラビリティーゾーンの行にチェックを入れてから、「サブネットを選択」のドロップダウンで
kms-vpce-lab-private-subnetを選ぶ(2段階の操作です) - セキュリティグループ:
kms-vpce-lab-endpoint-sg - ポリシー:
フルアクセス(後の手順で絞ります)




ページ下部の「エンドポイントを作成」をクリックします。
エンドポイントのステータスが「使用可能」になるまで数分待ちます。


手順3: エンドポイント経由で疎通することを確認する
手順1のターミナルに戻り、同じコマンドを再度実行します。
aws kms list-keys --region ap-northeast-1 --cli-connect-timeout 5 --cli-read-timeout 5今度はキーの一覧が返ることを確認します。アプリケーション側の設定は何も変えていません。プライベートDNSによって kms.ap-northeast-1.amazonaws.com の名前解決がエンドポイントのプライベートIPに変わったためです。
名前解決の結果も確認しておきます。
dig +short kms.ap-northeast-1.amazonaws.com10.20.1.x というVPC内のプライベートIPが返ることを確認します。





コマンドは何も変えていないのに、エンドポイントを作っただけで list-keys が通ったでござるな。プライベート DNS で kms.ap-northeast-1.amazonaws.com の名前解決が VPC 内のプライベート IP に変わった、というのが dig の結果からも分かるのでござる。
手順4: 経路を強制するキーポリシーを設定する
上部の検索バーに KMS と入力し、「Key Management Service」を選択します。
「カスタマー管理型のキー」から「キーの作成」で、エイリアス vpce-lab-key の対称キーを作成します。キーの管理者・使用者には自分のIAMユーザー(またはロール)と、kms-vpce-lab-instance-role を指定します。
作成したキーを開き、「キーポリシー」タブで「編集」をクリックします。既存のステートメントの末尾に、次のステートメントを追加します。vpce-xxxxxxxx は手順2で作成したエンドポイントのIDに置き換えます。
{
"Sid": "DenyAccessOutsideVpce",
"Effect": "Deny",
"Principal": "*",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-xxxxxxxx"
}
}
}

「変更の保存」をクリックします。
手順5: 経路によって結果が変わることを確認する
まずEC2のターミナル(エンドポイント経由)から暗号化を実行します。<キーID> は作成したキーのIDに置き換えます。
aws kms encrypt --key-id <キーID> --plaintext "$(echo -n 'hello' | base64)" --region ap-northeast-1暗号文が返ることを確認します。
次に、同じ操作をマネジメントコンソールから試します。KMSのキー詳細画面には暗号化を試す機能が無いため、ここではCloudShellまたは手元の端末のAWS CLIから同じコマンドを実行します。
aws kms encrypt --key-id <キーID> --plaintext "$(echo -n 'hello' | base64)" --region ap-northeast-1AccessDeniedException で拒否されることを確認します。同じIAM権限を持っていても、指定したVPCエンドポイントを経由していないためキーポリシーのDenyが効きます。





aws:sourceVpce の Deny を入れると、指定したエンドポイント以外からのリクエストはコンソールや S3 の SSE-KMS のような統合サービスからでも拒否されるのでござる。それと、VPC エンドポイント経由では aws:sourceIP が効かぬので、経路を絞るなら aws:sourceVpce か aws:sourceVpc を使うでござるぞ。
手順6: エンドポイントポリシーで絞る(任意)
VPCの「エンドポイント」画面で作成したエンドポイントを選択し、「ポリシー」タブの「ポリシーを編集」をクリックします。
「カスタム」を選び、次のように特定のキーだけを許可するポリシーに変更できます。
{
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["kms:Encrypt", "kms:Decrypt", "kms:DescribeKey"],
"Resource": "arn:aws:kms:ap-northeast-1:111122223333:key/<キーID>"
}
]
}エンドポイントポリシーはIAMポリシーやキーポリシーを置き換えるものではなく、その経路を通るリクエストに対する上限として働きます。3つが揃って初めて許可されます。





プライベートサブネットから AWS サービスへ安全に届かせたいとき、NAT ゲートウェイとインターフェイスエンドポイントのどちらを選ぶか、という観点が問われるのでござる。ゲートウェイ型はS3とDynamoDBのみという区別や、経路を縛る条件キーの選び方も、取り違えやすいところでござるな。
まとめ
| 論点 | 結論 |
|---|---|
| プライベートサブネットからKMSへ | インターフェイスVPCエンドポイント(PrivateLink)を使う |
| NATゲートウェイとの違い | インターネットに出ないこと、到達範囲がそのサービスに限られること、料金が抑えられること |
| アプリの変更 | プライベートDNSを有効にすれば不要。名前解決だけが変わる |
| 経路の強制 | キーポリシーの aws:sourceVpce / aws:sourceVpc 条件で行う |
| 注意点 | VPCエンドポイント経由では aws:sourceIP が効かない。経路を絞ると統合サービスやコンソールからの操作も拒否される |
- ゲートウェイ型はS3とDynamoDBのみ。KMSを含む多くのサービスはインターフェイス型を使う
- エンドポイントポリシー・IAMポリシー・キーポリシーは重ねて評価される。どれかで拒否されればアクセスできない
- 検証後はインターフェイスエンドポイントを削除する(時間課金が続くため)
参照先
- VPC エンドポイントを使用して AWS KMS に接続する – AWS Key Management Service
- VPC エンドポイントを使用して AWS KMS リソースへのアクセスを制御する – AWS Key Management Service
- AWS PrivateLink を使用して AWS のサービスにアクセスする – Amazon VPC
- インターフェイス VPC エンドポイント – AWS PrivateLink
- エンドポイントポリシーを使用して VPC エンドポイントへのアクセスを制御する – AWS PrivateLink










