Direct VPC Egress と Cloud NAT を使って Cloud Run functions の送信元 IP を固定してみた
データ事業本部のはんざわです。
皆さんは、外部サービス側でアクセス元 IP アドレス制限がある場合など、Cloud Run の送信元 IP を固定したくなることはないでしょうか?私も時々そのような要件に遭遇します。
以前は、Serverless VPC Access コネクタで VPC にトラフィックを流し、Cloud NAT で送信元 IP を固定する方法が一般的でした。
しかし現在では、Direct VPC Egress を使用することで、Serverless VPC Access コネクタを経由せずに、Cloud Run の各インスタンスに VPC サブネットの内部 IP を直接割り当てることが可能になりました。
この構成でも、従来どおり Cloud NAT を経由して送信元 IP を固定できます。
本ブログでは、実際に Cloud Run functions の送信元 IP を Direct VPC Egress と Cloud NAT を使って固定してみたいと思います。
どちらを使えば良いか?
現在は、Direct VPC Egress と Serverless VPC Access コネクタのどちらの方法でも送信元 IP を固定できます。
そのため、「どちらを使えば良いのか?」と疑問に思われるかもしれません。
結論としては、基本的には Direct VPC Egress の利用が推奨されています。
上記ドキュメントには両方式の比較表が掲載されています。
しかし、Direct VPC Egress にはいくつかの制限事項も存在するため、比較表と制限事項を確認した上で、要件に合った方式を選択してください。
試してみる
事前準備:ネットワークリソースの作成
まずは、必要なネットワークリソースを作成します。
すでに Serverless VPC Access コネクタを使用している状態から Direct VPC Egress に移行する場合は、これらのリソースを新たに作成する必要はありません。
しかし、Serverless VPC Access コネクタのインスタンスは起動したままのため料金が発生し続けます。移行が完了したら、コネクタを削除しておきましょう。
今回の構成では、Cloud Run から VPC 経由でインターネットに出るために、以下のネットワークリソースを用意します。
- 通信経路を収容する VPC
- Cloud Run に内部 IP を割り当てるためのサブネット
- Cloud NAT をぶら下げる Cloud Router
- 外向きの送信元として利用する固定 IP アドレス
- 内部 IP を外部 IP に変換する Cloud NAT
それぞれ、以下のコマンドで作成します。
- VPC
gcloud compute networks create vpc-cloud-run \
--subnet-mode=custom
参考:gcloud compute networks create
- サブネット
gcloud compute networks subnets create subnet-cloud-run \
--region=asia-northeast1 \
--network=vpc-cloud-run \
--range=10.10.10.0/24
参考:gcloud compute networks subnets create
- ルーター
gcloud compute routers create router-cloud-run \
--region=asia-northeast1 \
--network=vpc-cloud-run
参考:gcloud compute routers create
- IPアドレスの予約
gcloud compute addresses create static-ip \
--region=asia-northeast1
参考:gcloud compute addresses create
- Cloud NAT
gcloud compute routers nats create nat-cloud-run \
--router=router-cloud-run \
--region=asia-northeast1 \
--nat-all-subnet-ip-ranges \
--nat-external-ip-pool=static-ip
参考:gcloud compute routers nats create
事前準備:Cloud Run functions のデプロイ
ネットワークリソースを作成したら、検証用の Cloud Run functions をデプロイします。
今回の検証で実行するソースコードは以下の通りです。
https://api.ipify.org にアクセスして送信元 IP アドレスを取得し、その結果をログに出力するシンプルなコードです。
import requests
import functions_framework
@functions_framework.http
def main(request):
try:
response = requests.get('https://api.ipify.org?format=json', timeout=5)
if response.status_code == 200:
ip_data = response.json()
print(f"IP: {ip_data['ip']}")
else:
print("Failed to get IP")
except Exception as e:
print(f"Error: {e}")
return "OK"
このコードを次のコマンドでデプロイします。
gcloud run deploy direct-vpc-egress \
--source . \
--function main \
--base-image python313 \
--vpc-egress all-traffic \
--network vpc-cloud-run \
--subnet subnet-cloud-run \
--no-allow-unauthenticated \
--region asia-northeast1
コンソール上からも無事にデプロイできたことを確認できました。

動かしてみる
まず、Cloud NAT で利用している固定 IP アドレスを確認します。
gcloud compute addresses describe static-ip \ \
--region=asia-northeast1 \
--format='get(address)'
> 34.146.121.88
今回の検証では、この 34.146.121.88 が Cloud Run から外部サービスにアクセスする時の送信元 IP になる想定です。
次に、Cloud Shell から以下のコマンドを実行し、Cloud Run functions を呼び出します。
curl -X POST "https://direct-vpc-egress-<PROJECT_NUMBER>.asia-northeast1.run.app" \
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" \
-d '{}'
Cloud Logging に出力された IP アドレスが、上で確認した IP と一致していれば OK です。

はい、正常に IP を固定することができました。
まとめ
今回の検証では、Cloud Run functions の送信元 IP を Direct VPC Egress と Cloud NAT を組み合わせて固定してみました。
外部サービス側でアクセス元 IP アドレスを制限しているようなケースでは、とても有用なパターンだと思います。
本文中で紹介した比較表や制限事項も踏まえつつ、Direct VPC Egress と Serverless VPC Access コネクタを要件に応じて使い分けてみてください。
本ブログが参考になれば幸いです。






