はじめに
こんにちは!前回は Public → Isolated 方向の通信について詳しく解説しました。今回はシリーズを総括する形で、双方向 PrivateLink 設計(Isolated VPC ↔ Linked VPC/On-Prem) にフォーカスします。
「完全に隔離された Isolated VPC から、どうやってオンプレや社内ホストのツール(n8n / draw.io / ライセンスサーバー)へ安全にアクセスするの?」
「逆に、Linked 側から Isolated の社内 API にだけピンポイントで接続させたい」
この“両思い”を PrivateLink で叶える、実践的な設計指針を整理しました。😅
今回の内容(ロードマップ)
- 双方向 PrivateLink が必要になるユースケース
- アーキテクチャ全体像(両方向の接続パターン)
- 設計のキホン(Provider / Consumer、NLB、Interface VPC Endpoint、Private DNS)
- 代替案: Nginx 等の Proxy サーバーを置く設計 vs PrivateLink リスナーで管理する設計(メリデメ)
- サーバーレス運用のメリット(最小構成を保つ工夫)
- 最小 CDK スニペット(必要最小限のみ)
- よくある落とし穴と検証レシピ
- 次回予告(シリーズ構成を踏襲)
どんな時に「双方向 PrivateLink」?
代表ユースケース
- ライセンスサーバー(On-Prem): Isolated 側のビルド/解析ツールがオンプレのライセンス認証にアクセス(Outbound: Isolated → Linked/On-Prem)
- セルフホストの n8n / draw.io: 運用都合で社内 VPC やオンプレに置いたツールへ、Isolated の業務アプリや CI から安全に接続(Outbound)
- 社内 API ゲートウェイ: Linked 側の利用者やバッチから、Isolated にある限定 API へだけピンポイントに接続(Inbound: Linked → Isolated)
ポイント: 公開インターネットを使わず、TCP レベルでプライベートに接続できるのが PrivateLink。NAT 不要で最小構成にしやすいのが魅力です。
設計のキホン(おさらい)
- Provider 側(サービス提供元): NLB を背面に置いた VPC Endpoint Service を公開
- Consumer 側(サービス利用側): Interface VPC Endpoint を作成し、Provider の Endpoint Service に接続
- セキュリティ/運用: SG、Acceptance(明示許可)、Private DNS、ヘルスチェック、AZ 分散、最小権限 IAM
2つの接続パターン(両方向)
1) Linked → Isolated(Inbound 保護)
- 用途: Linked 側の利用者/ジョブから Isolated の API へピンポイント接続
- 設計: Provider=Isolated(NLB 配下の社内 API)、Consumer=Linked(Interface VPC Endpoint)
- 利点: 露出最小(必要なポート/宛先だけを NLB 経由で公開)
2) Isolated → Linked/On-Prem(Outbound 制御)
- 用途: Isolated 側の業務アプリ/CI から、社内ツール(n8n/draw.io)や On-Prem ライセンスサーバーへ
- 設計: Provider=Linked/On-Prem、Consumer=Isolated
- 利点: NAT 不要・踏み台不要。PrivateLink 宛のみ疎通を許可できる
代替案: Proxy サーバーを置く vs PrivateLink リスナーで管理
観点 | Proxy(Nginx/Squid 等) | PrivateLink リスナー(推し) |
---|---|---|
運用 | サーバー/パッチ/スケール管理が必要 | サーバーレス寄り(NLB + Endpoint Service / Fargate 最小) |
制御 | L7 フィルタ/Rewrite など柔軟 | L4 中心。“サービス単位で露出最小化”に強い |
コスト | EC2/NAT/運用工数が嵩むことも | NAT 不要で削減余地大(Endpoint AZ 課金は要考慮) |
セキュリティ | 自前でミドルの Hardening | AWS 管理のデータプレーン + IAM/SG/Acceptance |
可観測性 | L7 ログは取りやすい | Flow Logs + NLB HC、必要に応じ最小限のアプリログ |
結論: アプリ層の細工が本質でない限り、PrivateLink リスナー方式が“露出最小・運用最小・コスト最小”でハマりやすいです。
サーバーレス運用のメリット(最小構成で回す)
- NAT ゼロ: そもそも外へ出さない設計でコスト/面積を削る
- Fargate/ALB 不要構成も可: L4 なら NLB + Endpoint Service で完結
- IAM + SSM: 接続先ホワイトリストや接続承認を IaC & 最小権限で維持
- AZ 分散: Provider/Consumer ともに複数 AZ で HA を担保
最小 CDK スニペット(TypeScript|要点のみ)
余計な監視/長大コードはカット。Endpoint Service と Interface Endpoint の最短経路だけ示します。
// Provider (Linked/On-Prem 側 VPC): NLB + Endpoint Service
const nlb = new elbv2.NetworkLoadBalancer(this, 'SvcNlb', {
vpc, internetFacing: false
});
const listener = nlb.addListener('Tcp8080', { port: 8080 });
listener.addTargets('SvcTg', { port: 8080, targets: [/* IP/Instance/LB */] });
new ec2.VpcEndpointService(this, 'Svc', {
vpcEndpointServiceLoadBalancers: [nlb],
acceptanceRequired: true, // 明示許可
});
// Consumer (Isolated 側 VPC): Interface VPC Endpoint
new ec2.InterfaceVpcEndpoint(this, 'ToLinkedSvc', {
vpc,
service: new ec2.InterfaceVpcEndpointService(
`com.amazonaws.vpce.${cdk.Aws.REGION}.vpce-svc-xxxxxxxx`, 8080
),
subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
privateDnsEnabled: false,
securityGroups: [endpointSg],
});
メモ: 受け側ポートは NLB リスナーに合わせます(例: 8080)。Private DNS を張る場合は、名前解決計画(Route 53 Private Hosted Zone の関連付けや、アプリ側の接続先切替)を先に決めておくと移行が楽です。
よくある落とし穴
- Acceptance 忘れ: Consumer からの接続要求を Provider 側で未承認 → 永遠に繋がらない
- SG の両端漏れ: NLB 側の受け口と背面ターゲット、Endpoint 側の発信元/宛先を双方で許可
- HC ミス: NLB のヘルスチェックが HTTP で 200 を返せず Unhealthy → 接続できない
-
Private DNS 跨ぎ: 別アカウント/別 VPC 間での名前解決を後付けにして迷子に(
Private Hosted Zone の関連付け計画がカギ) - コスト見落とし: Endpoint の AZ ごとの時間課金/データ処理費用は試算する。とはいえ NAT 常設より軽いことが多い
検証レシピ(Isolated → On-Prem ライセンスサーバー)
- Provider: Linked/On-Prem 側で NLB:8080 → ライセンスサーバー(TCP)をターゲット登録
- Endpoint Service を作成、acceptanceRequired: true にする
- Consumer: Isolated 側で Interface Endpoint を作成(同 AZ を揃える)
- SG/Route を最小に調整(インターネットへは出さない)
-
疎通確認: Isolated の検証インスタンスから
nc -vz <endpoint-dns> 8080
、アプリから実際のハンドシェイク - 段階的切替: Private DNS を使う場合は CNAME で段階切替、問題なければ APEX を移行
まとめ
- 双方向 PrivateLink は、Isolated と Linked/On-Prem の必要最小限の面積で安全に繋ぐ最有力パターン
- Proxy 方式は柔軟だが“運用を抱えがち”。要件が L4 で足りるなら PrivateLink リスナー一択が多い
- 代表例: Isolated →(PrivateLink)→ ライセンスサーバー / n8n / draw.io、Linked →(PrivateLink)→ Isolated 内部 API
連載記事一覧 & 次回予告
- 第1回: PrivateLink 縛りの企業環境で双方向 VPC 連携アーキテクチャを設計してみた
- 第2回: CDK で作る PrivateLink スタック分割とデッドロック回避
- 第3回: Public → Isolated 通信編 – Provider を最小露出で守る
- 第4回: 双方向 PrivateLink 設計(本記事) – 代替案との比較と実践指針
- 次回(最終回): 運用の自動化 – Acceptance ワークフロー / Endpoint ローテーション / Blue-Green 切替 を IaC で回していく(お楽しみに!)