AWS PrivateLinkを使えば、VPCのCIDRアドレスが重複していてもAWSのプライベートネットワーク経由でサービスを安全に共有できます。
この記事では、
aws ec2コマンドを使ってPrivateLinkのエンドポイントサービス(プロバイダー側)とInterface型エンドポイント(コンシューマー側)を設計・作成する手順を解説します。NLBを介したマルチAZ冗長構成の実現方法から、EC2での接続確認まで一通り説明します。動作確認環境: Amazon Linux 2023(EC2)、AWS CLI v2.17以降
この記事のポイント
・aws ec2 create-vpc-endpoint-service-configurationでエンドポイントサービスを作成する
・NLBをバックエンドにすることでマルチAZ冗長のプライベートサービスを実現できる
・コンシューマー側はInterface型エンドポイントを作成するだけでVPC間接続が可能
・VPCピアリングと異なりCIDRアドレスが重複していても接続できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AWS PrivateLinkとは何か(VPCピアリングとの違い)
AWS PrivateLinkは、AWSのバックボーンネットワークを経由して、異なるVPC間でサービスをプライベートに提供する仕組みです。インターネットを経由せず、パブリックIPアドレスも不要なので、セキュリティ要件が厳しいシステム間連携に向いています。VPCピアリングとの主な違いは次のとおりです。
・VPCピアリング: 2つのVPC全体を相互接続する。CIDRの重複は不可。推移的ルーティング(A→B→C経由)も不可
・AWS PrivateLink: 特定のサービス(エンドポイント)だけを公開する。CIDRの重複があっても接続可能。VPC全体を公開しないためセキュリティ境界が明確
たとえば、社内の認証サービスや共有APIを複数のVPCから利用したい場合、PrivateLinkを使うとプロバイダーVPCの特定サービスだけを公開でき、VPC間でルーティングを全開放せずに済みます。アカウントをまたいだ接続も同じ手順で実現できます。
AWS環境のVPC設計・Linux基盤の構築を体系的に学ぶ方は、Amazon Linux × AWSの実践的な使い方もあわせてご覧ください。
PrivateLinkの構成要素(3つのコンポーネント)
AWS PrivateLinkを構成する主要な要素は3つです。・NLB(Network Load Balancer): プロバイダー側サービスのフロントエンド。マルチAZ配置にすることでバックエンドEC2への通信を複数AZに振り分けられる
・エンドポイントサービス: NLBに関連付けてプロバイダーが作成する論理的なサービス定義。コンシューマーが接続を要求する対象になる
・Interface型VPCエンドポイント: コンシューマーVPC内に作成するENI(Elastic Network Interface)。エンドポイントサービスへのプライベートDNSエントリが自動生成される
プロバイダー側の設定フローは「NLB作成 → エンドポイントサービス作成 → コンシューマーへのアクセス許可」の3ステップ、コンシューマー側は「Interface型エンドポイント作成」の1ステップで完結します。
プロバイダー側: NLBを作成してマルチAZ配置にする
まずバックエンドサービス(ここではTCP/8080で動くWebAPIを想定)に対してNLBを作成します。NLBを2つ以上のAZのサブネットに配置することで、AZ障害時でも別AZへの自動切り替えが働きます。1. VPCとサブネットを確認する
# VPC IDとCIDRを確認する aws ec2 describe-vpcs \ --query 'Vpcs[*].[VpcId,CidrBlock,Tags[?Key==`Name`].Value|[0]]' \ --output table # サブネットIDとAZを確認する(プロバイダーVPCのプライベートサブネット) aws ec2 describe-subnets \ --filters Name=vpc-id,Values=vpc-0a1b2c3d4e5f6a7b8 \ --query 'Subnets[*].[SubnetId,AvailabilityZone,CidrBlock,Tags[?Key==`Name`].Value|[0]]' \ --output table # 出力例(2つのAZにプライベートサブネットが存在することを確認) --------------------------------------------------------------- | DescribeSubnets | +-----------------------+-------------------+---------------+--+ | subnet-0a1b2c111111 | ap-northeast-1a | 10.0.10.0/24 | private-1a | | subnet-0a1b2c222222 | ap-northeast-1c | 10.0.20.0/24 | private-1c | +-----------------------+-------------------+---------------+--+
2. NLBを作成する(マルチAZ配置)
# NLBを作成する(ap-northeast-1a と ap-northeast-1c の2つのAZを指定) aws elbv2 create-load-balancer \ --name my-service-nlb \ --type network \ --subnets subnet-0a1b2c111111 subnet-0a1b2c222222 \ --scheme internal # 実行結果(抜粋) { "LoadBalancers": [ { "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/net/my-service-nlb/1a2b3c4d5e6f0001", "DNSName": "my-service-nlb-1234567890.elb.ap-northeast-1.amazonaws.com", "Type": "network", "Scheme": "internal", "State": { "Code": "provisioning" }, "AvailabilityZones": [ {"ZoneName": "ap-northeast-1a", "SubnetId": "subnet-0a1b2c111111"}, {"ZoneName": "ap-northeast-1c", "SubnetId": "subnet-0a1b2c222222"} ] } ] } # ターゲットグループを作成する(TCP/8080) aws elbv2 create-target-group \ --name my-service-tg \ --protocol TCP \ --port 8080 \ --vpc-id vpc-0a1b2c3d4e5f6a7b8 \ --target-type instance # バックエンドEC2をターゲットグループに登録する aws elbv2 register-targets \ --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/my-service-tg/abcd1234 \ --targets Id=i-0a1b2c3d4e5f11111 Id=i-0a1b2c3d4e5f22222 # NLBにリスナーを追加する(TCP/443) aws elbv2 create-listener \ --load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/net/my-service-nlb/1a2b3c4d5e6f0001 \ --protocol TCP \ --port 443 \ --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/my-service-tg/abcd1234
--scheme internalを指定することでNLBがプライベートIPアドレスのみを持つ内部ロードバランサーになります。PrivateLinkで使うNLBはinternalにするのが原則です。プロバイダー側: エンドポイントサービスを作成してコンシューマーを許可する
NLBの準備が完了したら、エンドポイントサービスを作成します。このリソースがPrivateLinkの「公開口」になります。3. エンドポイントサービスを作成する
# エンドポイントサービスを作成する aws ec2 create-vpc-endpoint-service-configuration \ --network-load-balancer-arns arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/net/my-service-nlb/1a2b3c4d5e6f0001 \ --no-acceptance-required # 実行結果(抜粋) { "ServiceConfiguration": { "ServiceType": [{"ServiceType": "Interface"}], "ServiceId": "vpce-svc-0a1b2c3d4e5f6a7b8", "ServiceName": "com.amazonaws.vpce.ap-northeast-1.vpce-svc-0a1b2c3d4e5f6a7b8", "ServiceState": "Available", "AvailabilityZones": [ "ap-northeast-1a", "ap-northeast-1c" ], "AcceptanceRequired": false, "NetworkLoadBalancerArns": [ "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/net/my-service-nlb/1a2b3c4d5e6f0001" ] } }
--no-acceptance-requiredを指定すると、コンシューマーがエンドポイントを作成した際に自動で承認されます。本番環境では省略(デフォルト: 承認必須)にして、許可リストで制御するのが安全です。4. コンシューマーアカウントへのアクセスを許可する
# コンシューマーのAWSアカウントIDを許可リストに追加する aws ec2 modify-vpc-endpoint-service-permissions \ --service-id vpce-svc-0a1b2c3d4e5f6a7b8 \ --add-allowed-principals arn:aws:iam::999888777666:root # 許可リストを確認する aws ec2 describe-vpc-endpoint-service-permissions \ --service-id vpce-svc-0a1b2c3d4e5f6a7b8 # 実行結果 { "AllowedPrincipals": [ { "PrincipalType": "Account", "Principal": "arn:aws:iam::999888777666:root" } ] }
コンシューマー側: Interface型エンドポイントを作成して接続する
コンシューマーアカウント(または別のVPC)でInterface型エンドポイントを作成します。この操作でコンシューマーVPCにENIが作成され、プライベートDNSエントリが自動生成されます。5. Interface型エンドポイントを作成する
# コンシューマー側: エンドポイントを作成する # (別アカウントのAWS CLI認証情報を設定して実行する) aws ec2 create-vpc-endpoint \ --vpc-id vpc-0f1e2d3c4b5a6b7c8 \ --vpc-endpoint-type Interface \ --service-name com.amazonaws.vpce.ap-northeast-1.vpce-svc-0a1b2c3d4e5f6a7b8 \ --subnet-ids subnet-0f1e2d3c4b5a11111 subnet-0f1e2d3c4b5a22222 \ --security-group-ids sg-0a1b2c3d4e5f12345 \ --private-dns-enabled # 実行結果(抜粋) { "VpcEndpoint": { "VpcEndpointId": "vpce-01234567890abcdef", "VpcEndpointType": "Interface", "VpcId": "vpc-0f1e2d3c4b5a6b7c8", "ServiceName": "com.amazonaws.vpce.ap-northeast-1.vpce-svc-0a1b2c3d4e5f6a7b8", "State": "pending", "DnsEntries": [ { "DnsName": "vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com", "HostedZoneId": "Z7HUB22UULQXV" } ], "NetworkInterfaceIds": [ "eni-0a1b2c3d4e5f11111", "eni-0a1b2c3d4e5f22222" ] } }
--subnet-idsに複数AZのサブネットを指定することで、各AZにENIが1つずつ作成されます。これがコンシューマー側のマルチAZ冗長の実体です。6. セキュリティグループを設定する
エンドポイントに関連付けたセキュリティグループ(sg-0a1b2c3d4e5f12345)には、コンシューマーEC2からエンドポイントへの通信を許可するインバウンドルールを設定します。# エンドポイント用SGのインバウンドルールを設定する(TCP/443をコンシューマーVPCのCIDRから許可) aws ec2 authorize-security-group-ingress \ --group-id sg-0a1b2c3d4e5f12345 \ --protocol tcp \ --port 443 \ --cidr 10.1.0.0/16 # エンドポイントのDNS名を一覧表示する aws ec2 describe-vpc-endpoints \ --vpc-endpoint-ids vpce-01234567890abcdef \ --query 'VpcEndpoints[0].DnsEntries[*].DnsName' # 出力(AZごとのDNS名も自動生成される) [ "vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com", "vpce-01234567890abcdef-zz1yy2xx-ap-northeast-1a.ap-northeast-1.vpce.amazonaws.com", "vpce-01234567890abcdef-zz1yy2xx-ap-northeast-1c.ap-northeast-1.vpce.amazonaws.com" ]
接続動作を確認する(EC2からのテスト)
エンドポイントの状態がavailableになったら、コンシューマーVPCのEC2からDNS名を使って接続できます。7. エンドポイントのステータスを確認する
# エンドポイントのステータスを確認する(available になるまで1~2分かかる) aws ec2 describe-vpc-endpoints \ --vpc-endpoint-ids vpce-01234567890abcdef \ --query 'VpcEndpoints[0].State' # 出力 "available" # コンシューマーEC2からDNS名解決を確認する [ec2-user@ip-10-1-0-50 ~]$ nslookup vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com Server: 10.1.0.2 Address: 10.1.0.2#53 Non-authoritative answer: Name: vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com Address: 10.1.10.45 Name: vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com Address: 10.1.20.67 # DNS解決結果がプライベートIPアドレス(10.x.x.x)であることを確認する # VPC外のパブリックIPには解決されていない = PrivateLink経由の通信になっている
8. EC2からHTTP接続を確認する
# curlでサービスのヘルスチェックエンドポイントに接続する [ec2-user@ip-10-1-0-50 ~]$ curl -v \ https://vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com/api/health \ --resolve 'vpce-01234567890abcdef-zz1yy2xx.ap-northeast-1.vpce.amazonaws.com:443:10.1.10.45' # 接続が成功した場合の出力(抜粋) * Trying 10.1.10.45:443... * Connected to ... (10.1.10.45) port 443 * SSL handshake completed < HTTP/1.1 200 OK {"status":"healthy"}
マルチAZ冗長設計の考え方
PrivateLinkのマルチAZ冗長は、NLBとInterface型エンドポイントの両側に複数のAZを設定することで実現します。・NLB側:
--subnetsに複数AZのサブネットを指定することでNLBがマルチAZ配置になる。AZ障害が発生すると正常なAZへのルーティングに自動で切り替わる・エンドポイント側: コンシューマーが
--subnet-idsに複数AZのサブネットを指定することで各AZにENIが作成され、AZ単位のフェイルオーバーが可能になる・AZアフィニティ: デフォルトでコンシューマーのトラフィックは同一AZ内のENIを優先してルーティングされる(クロスAZデータ転送コストの削減効果がある)
注意点として、エンドポイントサービスの提供AZ(
AvailabilityZones)とコンシューマーのエンドポイントサブネットが一致していないAZでは接続できません。事前にdescribe-vpc-endpoint-servicesで提供AZを確認しておきましょう。# エンドポイントサービスが提供するAZを確認する(コンシューマー側から実行) aws ec2 describe-vpc-endpoint-services \ --service-names com.amazonaws.vpce.ap-northeast-1.vpce-svc-0a1b2c3d4e5f6a7b8 \ --query 'ServiceDetails[0].AvailabilityZones' # 出力(プロバイダーがap-northeast-1a・1cで提供していることを確認) [ "ap-northeast-1a", "ap-northeast-1c" ]
設計上の注意点とコスト
・ENI時間課金: Interface型エンドポイントはENIが存在する時間に対して課金される(東京リージョンでENI1個あたり約$0.01/時間)。不要なエンドポイントは削除して無駄な課金を避ける・データ処理料金: エンドポイントを経由したデータ量に対しても課金される。大量データを転送する場合はコストを試算してからPrivateLinkを採用するか判断すること
・DNS設定の前提条件:
--private-dns-enabledを使うにはVPCで「DNSホスト名の有効化」と「DNS解決の有効化」の両方がオンになっている必要がある・NAT不要: PrivateLink経由の通信にNATゲートウェイは不要。コンシューマーEC2にパブリックIPがなくても接続できる
・承認設定: 本番環境では
--no-acceptance-requiredを省略し(デフォルトで承認必須)、コンシューマーからの接続要求をLambdaとEventBridgeを組み合わせて自動承認する運用が安全・VPC DNS属性の確認: コンシューマーVPCで
enableDnsHostnamesとenableDnsSupportが無効の場合、プライベートDNSが機能しない# VPCのDNS属性を確認する aws ec2 describe-vpc-attribute \ --vpc-id vpc-0f1e2d3c4b5a6b7c8 \ --attribute enableDnsHostnames aws ec2 describe-vpc-attribute \ --vpc-id vpc-0f1e2d3c4b5a6b7c8 \ --attribute enableDnsSupport # enableDnsHostnames の出力(trueであることが必要) { "VpcId": "vpc-0f1e2d3c4b5a6b7c8", "EnableDnsHostnames": { "Value": true } }
エンドポイントが接続できない時のトラブルシュート
PrivateLinkの設定後に接続できない場合、原因は大きく3つのパターンに分かれます。「vpce-svc-xxx does not exist」エラーが出る場合
コンシューマー側でcreate-vpc-endpointを実行した際にサービスが見つからないエラーが出るケースです。・プロバイダー側でコンシューマーアカウントのARNが許可リストに登録されているか確認する
・
describe-vpc-endpoint-service-permissionsでAllowedPrincipalsを確認する・サービス名(
com.amazonaws.vpce.リージョン.vpce-svc-xxx)に誤りがないか確認する# プロバイダー側: 許可リストを確認する aws ec2 describe-vpc-endpoint-service-permissions \ --service-id vpce-svc-0a1b2c3d4e5f6a7b8 \ --query 'AllowedPrincipals[*].Principal' # 出力(コンシューマーアカウントのARNが含まれているか確認) [ "arn:aws:iam::999888777666:root" ]
エンドポイントのStateがpendingのまま変わらない場合
プロバイダー側でAcceptanceRequiredが有効になっているにもかかわらず、承認操作が行われていない場合に発生します。・プロバイダー側でエンドポイント接続要求を確認して承認する
# プロバイダー側: 承認待ちの接続要求を確認する aws ec2 describe-vpc-endpoint-connections \ --filters Name=vpc-endpoint-service-id,Values=vpce-svc-0a1b2c3d4e5f6a7b8 \ --query 'VpcEndpointConnections[?VpcEndpointState==`pendingAcceptance`].[VpcEndpointId,VpcEndpointState]' # 承認操作を実行する aws ec2 accept-vpc-endpoint-connections \ --service-id vpce-svc-0a1b2c3d4e5f6a7b8 \ --vpc-endpoint-ids vpce-01234567890abcdef
DNS名がプライベートIPに解決されない場合
コンシューマーVPCで「DNSホスト名の有効化」または「DNS解決の有効化」が無効になっているケースです。・
describe-vpc-attributeでenableDnsHostnamesとenableDnsSupportが両方trueであることを確認する・どちらかがfalseの場合は
modify-vpc-attributeで有効化する# DNS属性を有効化する(コンシューマーVPCで実行) aws ec2 modify-vpc-attribute \ --vpc-id vpc-0f1e2d3c4b5a6b7c8 \ --enable-dns-hostnames aws ec2 modify-vpc-attribute \ --vpc-id vpc-0f1e2d3c4b5a6b7c8 \ --enable-dns-support
本記事のまとめ
| やりたいこと | コマンド |
|---|---|
| NLBをマルチAZ配置で作成する | aws elbv2 create-load-balancer --type network --subnets サブネット1 サブネット2 --scheme internal |
| エンドポイントサービスを作成する | aws ec2 create-vpc-endpoint-service-configuration --network-load-balancer-arns NLBのARN |
| コンシューマーアカウントを許可する | aws ec2 modify-vpc-endpoint-service-permissions --service-id vpce-svc-xxx --add-allowed-principals arn:aws:iam::ACCOUNT_ID:root |
| Interface型エンドポイントを作成する | aws ec2 create-vpc-endpoint --vpc-endpoint-type Interface --service-name サービス名 --subnet-ids サブネット1 サブネット2 |
| エンドポイントのDNS名を確認する | aws ec2 describe-vpc-endpoints --vpc-endpoint-ids vpce-xxx --query 'VpcEndpoints[0].DnsEntries[*].DnsName' |
| 提供AZを確認する | aws ec2 describe-vpc-endpoint-services --service-names サービス名 --query 'ServiceDetails[0].AvailabilityZones' |
VPC設計全般やAmazon Linux環境でのサーバー運用を体系的に習得したい方は、Amazon Linux × AWSの実践的な使い方からはじめるのがおすすめです。
AWS PrivateLinkを実務で使いこなすには、VPC設計の「型」が必要です
PrivateLinkでVPC間をセキュアに接続するには、VPCの設計原則・セキュリティグループ・ルーティングを体系的に理解することが重要です。断片的な知識の寄せ集めではなく、現場で実際に使われる設計パターンを一度体系的に身につけることで、安全なクラウド基盤が構築できるようになります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AWS Route 53プライベートホストゾーンでVPC内DNSを設計する方法|マルチVPC対応とResolver Endpointのオンプレミス連携まで
- この記事の属するカテゴリ:AWS(Amazon Linux)へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます