AWS PrivateLinkとは
AWS PrivateLink は、AWS 内部ネットワークを通じてサービス提供者(Provider)と利用者(Consumer)をつなぐ仕組みです。
本記事では、Provider アカウントの VPC 内でホストする Web アプリケーションを、Consumer アカウントのプライベートサブネットにある EC2 から PrivateLink 経由でアクセスできるようにする手順を、Terraformを利用してハンズオン形式で説明します。
構成図
1. リポジトリ概要
本記事で利用するコードは GitHub の super-masaya/AWS-PrivateLink-kensyou リポジトリにまとまっています。下記の手順でローカルにコードを用意してください。
git clone https://github.com/super-masaya/AWS-PrivateLink-kensyou.git
cd AWS-PrivateLink-kensyou
ディレクトリ構成(抜粋)
├── provoder/      # Provider アカウント側の Terraform 定義
│   ├── main.tf
│   ├── variable.tf
│   ├── terraform.tfvars.example
│   └── ...
├── consumer/      # Consumer アカウント側の Terraform 定義
│   ├── main.tf
│   ├── variable.tf
│   ├── terraform.tfvars.example
│   └── ...
2. 前提条件
| カテゴリ | 必須内容 | 補足 | 
|---|---|---|
| AWS アカウント | Provider / Consumer の 2 アカウント | 2つのアカウントを用意してください。 | 
| IAM 権限 | VPC・EC2・IAM・ELB・PrivateLink 周りの作成/更新権限 | AdministratorAccess相当 | 
| Terraform | v1.0 以上 | 事前に terraform コマンドが利用できること(terraform -v で確認) | 
| AWS CLI | (プロファイル provider-account, consumer-account を設定) | 
|
| リージョン | 
ap-northeast-1(東京) | 
他リージョンで試す場合は各種 AMI や AZ 名を読み替えてください | 
| コスト | EC2 と NLB、Interface/ Gateway Endpoint の時間課金 | ハンズオン後は「片付け」セクションに従って destroy を忘れずに | 
3. 事前準備
3.1 AWS CLI プロファイル設定例
# Provider アカウント
aws configure --profile provider-account
aws configure list --profile provider-account
# Consumer アカウント
aws configure --profile consumer-account
aws configure list --profile consumer-account
3.2 変数ファイルの準備
- 
provoder/terraform.tfvars.exampleをコピーし、consumer_account_idやネットワーク CIDR を環境に合わせて設定 - 
consumer/terraform.tfvars.exampleでは Provider 側から払い出されるservice_nameを後で設定 
cp provoder/terraform.tfvars.example provoder/terraform.tfvars
cp consumer/terraform.tfvars.example consumer/terraform.tfvars
4. Provider 側インフラの構築
- プロファイルを Provider に切り替えます。
export AWS_PROFILE=provider-account - Terraform を実行します。
initでプラグインを取り込み、planで差分を確認した上でapplyします。apply実行中に表示される確認プロンプトではyesを入力してください。cd provoder terraform init terraform plan terraform apply - 正常にデプロイできたら、Consumer 側で使う VPC エンドポイントサービス名を控えておきます。
terraform output service_name 
Provider 側で作成される主なリソース
- VPC / Private Subnet / ルートテーブル
 - Network Load Balancer(PrivateLink のエントリーポイント)
 - VPC Endpoint Service(手動承認あり)
 - Web サーバー EC2(Apache)
 - S3 Gateway Endpoint(YUM リポジトリ用)
 - SSM エンドポイント + IAM ロール/インスタンスプロファイル
 
5. Consumer 側インフラの構築
- プロファイルを Consumer に切り替えておきます。
export AWS_PROFILE=consumer-account - 
consumer/terraform.tfvarsのservice_nameに、Provider 側で取得した値を設定します。 - Terraform を適用します。
cd ../consumer terraform init terraform plan terraform apply 
Consumer 側で作成される主なリソース
- VPC / Private Subnet / ルートテーブル
 - Interface VPC Endpoint(PrivateLink への接続ポイント)
 - テスト用 EC2(Session Manager 対応済み)
 - S3 Gateway Endpoint / SSM エンドポイント
 - EC2 用 IAM インスタンスプロファイル
 
6. VPC エンドポイント接続の承認
Consumer 側からの接続リクエストは自動承認されません。Provider 側でリクエストを承認します。
リクエストの承認手順
- 
Provider アカウントのコンソールにログイン
 - 
VPC → エンドポイントサービス を開く
 - 
対象のエンドポイントを選択して、アクションから「エンドポイント接続リクエストの承認」を選択する。
 
5 . Pending acceptance のリクエストを選択して「承認」

6 . ステータスが Available になれば完了
7. 動作確認
6.1 PrivateLink 経由の HTTP 応答
- Consumer 側 Terraform の出力 
endpoint_dns_nameを控えます。 - Systems Manager → Session Manager からテスト用 EC2 にセッション接続。
 - インスタンス内で以下を実行し、Apache のレスポンスを確認します。
//qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4077172/140c3435-f2aa-4b0f-898f-4b23dad05464.png)
curl http://<endpoint_dns_name><h1>Cross-Account PrivateLink Service</h1>と表示されれば成功です。 
8. 片付け(クリーンアップ)
検証が終わったら、Consumer → Provider の順で下記コマンドから後片付け(リソースの削除)をしてください。
export AWS_PROFILE=consumer-account
cd consumer
terraform destroy -auto-approve
export AWS_PROFILE=provider-account
cd ../provoder
terraform destroy -auto-approve
9. まとめ
現場でAWS PrivateLinkの仕組みについて沼っていたのでこの機会に記事にしました。
裏ではセキュリティグループやNLBの設定で深淵を覗いていたことはまたどこかの機会で記事にできればと思います(笑)
PrivateLink を触れる前は独立したサービスだと思ってましたが、誤解だった。
実体は「VPC Endpoint Service + Interface VPC Endpoint」の組み合わせでPrivateLink」は技術の総称であって、単一リソースではない
VPC Endpoint (総称)
├── Gateway Endpoint (S3, DynamoDB)
└── Interface Endpoint (PrivateLink)
├── AWS サービス用 (Lambda, SNS等)
└── カスタムサービス用 ← これが今回の検証
承認フローの存在を見落とし
Consumer 側が永遠に Pending acceptance で詰まる
実務ではProvider側に承認してくれ〜と頼むが一般的な運用フローなのですかね?何にせよ仕組みを理解していないと永遠にPending acceptance で詰まってしまいますね(笑)(実体験)



