Photo by Ar_TH from Shutterstock
はじめに
クラウドコンピューティングの世界では、アプリケーションやサービスを安定して稼働させるうえでネットワーク管理が欠かせません。その基本となるのが、クラウド環境内の各リソースへのIP(インターネットプロトコル)アドレスの割り当てです。IPアドレスはクラウドリソースを識別する役割を担い、リソース同士やインターネットとの通信を可能にします。
オンプレミス環境であれ、Google Cloud Platform(GCP)のようなクラウド基盤であれ、ネットワークを設計する際には「重複するIPアドレス範囲」と「重複しないIPアドレス範囲」という考え方が登場します。
重複するIPアドレス範囲とは、2つ以上のIPアドレス範囲に共通のアドレスが含まれ、互いに重なり合っている状態を指します。
重複しないIPアドレス範囲とは、それぞれのアドレスが一意で、他の範囲のアドレスとまったく重ならないIPアドレスの集合です。
GCPの各Virtual Private Cloud(VPC)ネットワークは1つ以上のサブネットで構成されており、他のVPCのIPアドレス範囲と重複する場合もあれば、重複しない場合もあります。重複するサブネット間ではデフォルトでプライベートネットワークアクセスが許可されないため、サブネットには重複しないIPアドレス範囲を割り当てることが非常に重要です。
以前の記事では、Private Service Connect(PSC)を使い、IP範囲が重複するVPCネットワーク内のサービスにプライベートアクセスする方法をご紹介しました。
GCPでは最近、重複するネットワーク間のプライベート通信を実現するPrivate NATがプレビューとして提供されました。本記事では、IP範囲が重複するVPCと重複しないVPCをまたいで稼働するサービスにプライベートアクセスするために、Inter-VPC NATを設定する方法を解説します。
**Inter-VPC NAT**とは?
GCPでは、VPC間で特定のサブネットを共有できないため、重複するネットワーク同士でVPCピアリングを行うことはできません。Inter-VPC NATはPrivate NATゲートウェイの一種で、type=PRIVATEのNAT構成を用いることで、別のVPCを経由して、重複するサブネット内のVPCネットワークリソースが、(他のサブネットが重複していたとしても)重複しないサブネット内のリソースと通信できるようにします。
Inter-VPC NATはNetwork Connectivity Centerと連携して動作します。Network Connectivity Centerは、ネットワーク接続を一元的かつシンプルに管理できる統合システムです。Google Cloudのさまざまなネットワーキング機能を1つのインターフェースに集約し、クラウドとオンプレミスのネットワークを容易に接続・管理できるよう設計されています。
Network Connectivity Centerは、ネットワーク接続にハブ&スポークモデルを採用しています。ハブはVirtual Private Cloud(VPC)ネットワークに対する接続の中心点であり、各スポークからの接続を集約する仮想ルーターのような存在と考えるとわかりやすいでしょう。スポークにはVPN、Interconnect、サードパーティ製ルーター、または他のVPCネットワークなどがあります。
VPCネットワーク間でInter-VPC NATを利用するには、各VPCネットワークをNetwork Connectivity CenterハブのVPCスポークとして構成する必要があります。VPCスポークを使えば、複数のVPCネットワークを接続し、VPCピアリングでは実現できなかった特定のIPv4サブネットルートの交換が可能になります。これにより、これらのVPCネットワーク内に存在するすべてのworkloads間で、完全なIPv4接続を確保できます。
スポークを作成する際は、重複するIPアドレス範囲が他のVPCスポークに共有されないように設定してください。
制限事項
プレビュー時点でのInter-VPC NATには、以下のような主な制限があります。
- Inter-VPC NATはEndpoint-Independent Mappingに対応していません。
- クロスプロジェクト対応のInter-VPC NATはプレビューでは利用できません。
- Inter-VPC NATのロギングはプレビューでは利用できません。
- プレビューでは、既存のPrivate NATゲートウェイを更新する際にgcloud CLIのみを使用してください。Google Cloudコンソールから更新すると、構成が不正になる可能性があります。
- Inter-VPC NATがサポートするのはTCPおよびUDP接続のみです。
- Inter-VPC NATによるネットワークアドレス変換(NAT)は、Network Connectivity CenterのVirtual Private Cloud(VPC)スポーク間でのみサポートされ、VPC Network Peeringで接続されたVirtual Private Cloudネットワークには対応しません。
- VPCネットワーク内の仮想マシン(VM)インスタンスからアクセスできるのは、ピアリング先ネットワークの重複しないサブネットワーク内の宛先のみで、重複するサブネットワーク内の宛先にはアクセスできません。
これらの制限の一部は、GAまでに解消される可能性があります。最新情報は公式ドキュメントをご確認ください。
リファレンスアーキテクチャ
本構成では、vpc-aとvpc-bがIPアドレス範囲の重複するサブネットを持っています。vpc-bには、サンプルアプリケーションをホストする重複しないサブネットも存在します。
vpc-aにPrivate NATゲートウェイをデプロイし、重複するサブネット内のインスタンスから、重複しないサブネット内のサンプルアプリケーションへ接続できるようにします。

https://cloud.google.com/nat/docs/private-nat#pvt-nat-flow-example
ネットワークの構築とサンプルアプリケーションのデプロイ
ステップ1: 必要な環境変数を設定します。
export PROJECT_ID="your-project-id" #ex: chimbu-playground
export VPC_A_SUBNET_REGION="us-east1"
export VPC_A_SUBNET_A_CIDR="192.168.1.0/24"
export VPC_B_SUBNET_REGION="us-west1"
export VPC_B_SUBNET_B_CIDR="192.168.2.0/24" #non-overlapping subnet between vpc-a and vpc-b
export VPC_B_SUBNET_C_CIDR="192.168.1.0/24" #overlapping subnet between vpc-a and vpc-b
export VPC_A_PRIVATE_NAT_GW_CIDR="10.1.2.0/29"
ステップ2: VPCネットワークとサブネットを作成します。
#Create vpc-a custom Network and subnet
gcloud beta compute networks create vpc-a \
--subnet-mode=custom
gcloud beta compute networks subnets create subnet-a \
--network="vpc-a" \
--role="ACTIVE" \
--purpose="PRIVATE" \
--range=$VPC_A_SUBNET_A_CIDR \
--region=$VPC_A_SUBNET_REGION
# Create vpc-b custom Network and subnets
gcloud beta compute networks create vpc-b \
--subnet-mode=custom
gcloud beta compute networks subnets create subnet-b \
--network="vpc-b" \
--role="ACTIVE" \
--purpose="PRIVATE" \
--range=$VPC_B_SUBNET_B_CIDR \
--region=$VPC_B_SUBNET_REGION
gcloud beta compute networks subnets create subnet-c \
--network="vpc-b" \
--role="ACTIVE" \
--purpose="PRIVATE" \
--range=$VPC_B_SUBNET_C_CIDR \
--region=$VPC_B_SUBNET_REGION
ステップ3: VMインスタンスへのSSHアクセスを可能にするため、Identity-Aware Proxy(IAP)TCP転送用のファイアウォールルールを作成します。
このあとの手順では外部IPを持たないVMインスタンスを作成します。IAP TCP転送を使うと、暗号化されたトンネル経由でSSHやRDPなどのトラフィックをVMインスタンスへ転送できます。
TCP転送および関連する操作を実行できるよう、ユーザーにroles/iap.tunnelResourceAccessorロールが付与されていることを確認してください。
gcloud compute firewall-rules create vpc-a-iap \
--direction=INGRESS \
--priority=1000 \
--network=vpc-a \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20
gcloud compute firewall-rules create vpc-b-iap \
--direction=INGRESS \
--priority=1000 \
--network=vpc-b \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20
ステップ4: インターネットアクセス用のCloud NATインスタンスを作成します。このCloud NATはVPC間のプライベート通信を許可するものではありません。VPC間通信は別途構成します。
#vpc-a Cloud router and NAT
gcloud compute routers create vpc-a-internet-nat-router \
--network=vpc-a \
--region=$VPC_A_SUBNET_REGION
gcloud beta compute routers nats create vpc-a-internet-nat \
--router=vpc-a-internet-nat-router \
--nat-all-subnet-ip-ranges \
--region=$VPC_A_SUBNET_REGION \
--auto-allocate-nat-external-ips
#vpc-b Cloud router and NAT
gcloud compute routers create vpc-b-internet-nat-router \
--network=vpc-b \
--region=$VPC_B_SUBNET_REGION
gcloud beta compute routers nats create vpc-b-internet-nat \
--router=vpc-b-internet-nat-router \
--nat-all-subnet-ip-ranges \
--region=$VPC_B_SUBNET_REGION \
--auto-allocate-nat-external-ips

ネットワーク内のCompute Engineインスタンスにインターネットアクセスを提供するCloud NAT
ステップ5: 外部IPを持たないテスト用Compute Engineインスタンスを作成します。
#Test instance in vpc-a network and subnet-a
gcloud compute instances create vpc-a-subnet-a-test \
--project=$PROJECT_ID \
--zone="us-east1-b" \
--machine-type=e2-medium \
--network-interface=stack-type=IPV4_ONLY,subnet=subnet-a,no-address \
--tags=http-server \
--create-disk=auto-delete=yes,boot=yes,device-name=vpc-a-subnet-a-test,image=projects/debian-cloud/global/images/debian-11-bullseye-v20230814,mode=rw,size=10,type=projects/$PROJECT_ID/zones/us-east1-b/diskTypes/pd-balanced
#Test instance in vpc-b network and subnet-b, Also deployed nginx service.Cloud NAT to download the required ngninx packages.
gcloud compute instances create vpc-b-subnet-b-test \
--project=$PROJECT_ID \
--zone="us-west1-a" \
--machine-type=e2-medium \
--network-interface=stack-type=IPV4_ONLY,subnet=subnet-b,no-address \
--metadata=startup-script=\#/bin/sh$'\n'sudo\ \
apt\ update$'\n'sudo\ apt\ install\ nginx\ -y\ \
--tags=http-server \
--create-disk=auto-delete=yes,boot=yes,device-name=vpc-b-subnet-b-test,image=projects/debian-cloud/global/images/debian-11-bullseye-v20230814,mode=rw,size=10,type=projects/$PROJECT_ID/zones/us-west1-a/diskTypes/pd-balanced
#Test instance deployed in vpc-b network and subnet-c
gcloud compute instances create vpc-b-subnet-c-test \
--project=$PROJECT_ID \
--zone="us-west1-a" \
--machine-type=e2-medium \
--network-interface=stack-type=IPV4_ONLY,subnet=subnet-c,no-address \
--tags=http-server \
--create-disk=auto-delete=yes,boot=yes,device-name=vpc-b-subnet-c-test,image=projects/debian-cloud/global/images/debian-11-bullseye-v20230814,mode=rw,size=10,type=projects/$PROJECT_ID/zones/us-west1-a/diskTypes/pd-balanced

Compute Engineインスタンス
この時点では、vpc-a内のvpc-a-subnet-a-testインスタンスから、vpc-b-subnet-b-testインスタンスで稼働するサービスにはアクセスできません。両者の間にネットワーク接続が存在せず、サブネットが重複しているためVPCピアリングも作成できないためです。
Network Connectivity Centerでハブとスポークを構築する
サブネットIP範囲が重複する2つのVPCネットワーク間で通信できるようにするには、両方のVPCネットワークを同じNetwork Connectivity CenterハブにVPCスポークとして接続する必要があります。
ステップ6: Network Connectivity Centerのハブを作成します。
gcloud network-connectivity hubs create private-nat-demo-vpc-hub

ステップ7: VPCネットワークをスポークとしてハブに追加します。重複するネットワークがエクスポート対象から除外されていることを確認してください。
#Add vpc-a to the hub and exclue VPC_A_SUBNET_A_CIDR from export.
gcloud network-connectivity spokes linked-vpc-network create vpc-a \
--hub="https://www.googleapis.com/networkconnectivity/v1/projects/$PROJECT_ID/locations/global/hubs/private-nat-demo-vpc-hub" --global \
--vpc-network="https://www.googleapis.com/compute/v1/projects/$PROJECT_ID/global/networks/vpc-a" \
--exclude-export-ranges=$VPC_A_SUBNET_A_CIDR
#Add vpc-b to the hub and exclue VPC_B_SUBNET_C_CIDR from export.VPC_B_SUBNET_B_CIDR will be exported between the VPCs.
gcloud network-connectivity spokes linked-vpc-network create vpc-b \
--hub="https://www.googleapis.com/networkconnectivity/v1/projects/$PROJECT_ID/locations/global/hubs/private-nat-demo-vpc-hub" --global \
--vpc-network="https://www.googleapis.com/compute/v1/projects/$PROJECT_ID/global/networks/vpc-b" \
--exclude-export-ranges=$VPC_B_SUBNET_C_CIDR

VPCスポーク

VPC間で交換されたルート
Inter-VPC NATを構築する
Inter-VPC NATには、用途がPRIVATE_NATに設定された専用サブネットが必要です。Private NATゲートウェイは、このサブネットのIPアドレス範囲を使ってNATを行います。このサブネットは、同じNetwork Connectivity Centerハブに接続されているどのVPCスポークの既存サブネットとも重複してはいけません。また、このサブネットはPrivate NAT専用に使われます。
ステップ8: Private NAT用のサブネットを作成します。vpc-bで稼働するサービスにアクセスする必要があるため、サブネットはvpc-a内に作成します。Private NATは送信リクエストに対してのみNATを行います。
gcloud beta compute networks subnets create private-nat-gateway \
--network=vpc-a \
--region=$VPC_A_SUBNET_REGION \
--range=$VPC_A_PRIVATE_NAT_GW_CIDR \
--purpose=PRIVATE_NAT

ステップ9: Cloud RouterとPrivate NATゲートウェイを作成します。
gcloud compute routers create vpc-a-private-nat-gw-router \
--network="vpc-a" \
--region=$VPC_A_SUBNET_REGION
gcloud beta compute routers nats create vpc-a-private-nat-gw \
--router=vpc-a-private-nat-gw-router \
--type=PRIVATE \
--nat-all-subnet-ip-ranges \
--region=$VPC_A_SUBNET_REGION
ステップ10: Private NATゲートウェイにNATルールを作成し、送信元のVPCスポークから、同じNetwork Connectivity Centerハブに接続されているピアVPCスポークへ流れる送信トラフィックに対してNATを実行します。このNATルールに基づいて、Private NATゲートウェイはPrivate NATサブネットからNAT用のIPアドレスを割り当て、トラフィックにNATを適用します。
gcloud beta compute routers nats rules create 1000 \
--router=vpc-a-private-nat-gw-router \
--nat=vpc-a-private-nat-gw \
--match='nexthop.hub == "//networkconnectivity.googleapis.com/projects/chimbuc-playground/locations/global/hubs/private-nat-demo-vpc-hub"' \
--source-nat-active-ranges=private-nat-gateway \
--region=$VPC_A_SUBNET_REGION

Private NATゲートウェイ
ステップ11: Private NATゲートウェイからの接続を許可するために、vpc-bにファイアウォールルールを作成します。
gcloud compute firewall-rules create vpc-b-allow-ingress-private-nat-gw \
--direction=INGRESS \
--priority=1000 \
--network=vpc-b \
--action=ALLOW \
--rules=tcp \
--source-ranges=$VPC_A_PRIVATE_NAT_GW_CIDR
ステップ12: vpc-aとvpc-bの各ネットワーク間の接続をテストします。

スクリーンショットのとおり、vpc-a内のインスタンスからInter-VPC NAT経由でvpc-bの重複しないサブネットで稼働するサービスにアクセスできていることが確認できます。
Inter-VPC NATは、重複するネットワーク間のプライベート通信をシンプルに実現できる強力な仕組みです。Inter-VPC NATを使えば、あるリソースが他のサブネットと重複するサブネットに配置されていても、別のVPC内の重複しないサブネット上のリソースとプライベートに通信できます。
重複するサブネット同士のプライベート通信には、Private Service Connectもあわせてご活用ください。本記事がお役に立てば幸いです。ご質問があればお気軽にお問い合わせください。