grasys blog

Cloud Functionsで固定IPを使ったIngress/Egress設定

こんにちは!
個人的に使ってるPCが6年目を迎え、いろんな寿命を感じているので諸々の買い替えを検討しているtokuraです。メモリやらストレージやら何やらと必要なものを調べると想像以上に検討事項が多くて大変です…..。

さて、今回はクラウド上で特定のインスタンスを使用せずにwebhookを効率的に運用できるようにするCloud Run Functionsの設定について、です。
Cloud Functions は 2024年8月にCloud Run ベースへ統合されて使いやすさが向上しました。
本記事では、Cloud Functions で作成したwebhookを特定 IP からのアクセスのみに制限しつつ、webhookから固定外部 IP へ接続する構成を構築していきます。

この記事で得られるもの

  1. Cloud Functions(webhook) の Ingress と Egress の設定
    • Ingress – HTTPS Load Balancer + Serverless NEG を用いた IP 制限
    • Egress – Serverless VPC Connector + Cloud NAT による固定 Egress
  2. webhookの/healthz エンドポイントと 稼動時間チェックによる死活監視

各設定について

1) Ingress: 外部 → Cloud Functionsへの接続設定

  • HTTPS Load Balancer + Serverless NEG
    Function を公開せず、ロードバランサ経由でのアクセスに限定
  • Cloud Armor Security Policy
    許可された CIDR のみからのアクセスに限定

2) Egress: Functions → 外部接続 の接続設定

  • Serverless VPC Connector
    Cloud Functions から VPC 経由で通信
  • Cloud NAT + 固定外部 IP
    一貫した Egress IP による外部サービス接続

3) 死活監視

  • Cloud Monitoring Uptime Check
    /healthz エンドポイントを用いた定期的な可用性チェック

リソース作成


リソースの作成はTerraformでもgcloudコマンドでも。terraformの方が管理しやすいので今回terraform。

主にリソース名のみ書き出していくのでリソースの中身で必要な書き方については公式を参照ください。

設定時に気をつけた部分については書き出してます。

1) Ingress


まずはサーバレスNEGを設定します。
外部からアクセスしたいfunctionsを名指ししてサーバレスNEGを作成してください。

resource "google_compute_region_network_endpoint_group" "function_neg" {
  name                  = "function-neg"
...
  cloud_function {
    function = "tokura_function001"
  }
}

functionsのインスタンスIPはインスタンスが入れ替わるたびに動的に変わるので、この前段に外部LBを配置して固定IPでアクセスできるようにします。
LBにはアクセスしたいドメインやssl証明書とか付けることができるので今回作成するリソースはそれぞれ以下。

アクセスするIP (ドメイン追加)
resource "google_compute_global_address" "lb_global_address"
resource "google_dns_record_set" "functions"

httpsでアクセス
resource "google_compute_managed_ssl_certificate" "ssl_cert" 
resource "google_compute_target_https_proxy" "https_proxy" 
resource "google_compute_global_forwarding_rule" "https_rule"
resource "google_compute_url_map" "url_map" 

アクセスするIPの制限
resource "google_compute_backend_service" "backend" 
resource "google_compute_security_policy" "allow_ips" 

このリソース作成で特定IPからfunctionへアクセスする準備はできました。

次にfunctionデプロイ時に追加するものについて。

functionはhttp関数でデプロイしますが、デプロイ時のオプションに以下を加えます。

--ingress-settings internal-and-gclb \
--allow-unauthenticated 

これによってLB経由でのアクセスが可能になります。

2) Egress


次に function-> 外部IPを持つCloudSQL (mysql)インスタンスへのアクセスの設定について。
まずはfunctionインスタンスが外部に出るための経路を用意します。
この時必要になるのがServerless VPC Connector + CloudNAT
以下こんな感じのtfリソース

resource "google_vpc_access_connector" "vpc-connector" {
  name          = "tokura-vpc-connector"
...
  ip_cidr_range = "(INTERNAL_IP)/28"
...
  region        = "asia-northeast1"
}

VPC アクセスコネクターでは一定の内部IPサブネットが必要です。IPの範囲はネットワーク内で使われてない/28以上です。またリージョンもfunctionをデプロイしているリージョンと揃えましょう。

そしてVPCコネクターも一時的なインスタンスなので、接続したい外部IPに向ける以下のリソースを準備

resource "google_compute_address" "nat_static_ip" 
resource "google_compute_router" "nat_router" 
resource "google_compute_router_nat" "nat_rule" 

この時にfunctions側では以下の設定を追加します。

--vpc-connector $CONNECTOR_NAME \
--egress-settings all-traffic

さらに接続するCloudSQLインスタンスには承認済みネットワークにIPを追加する必要があります。

この時に追加するのは上記で作成したresource “google_compute_address” “nat_static_ip” のリソースです。

CloudSQLへの接続情報は実装次第かと思われますが、下記のようにfunctionデプロイ時にオプションを追加してfunctionが利用できるように。

--set-env-vars XX_XX_DB_HOST=XX-XX-XX

死活監視

CloudFunctionではCloud Monitoringの稼動時間チェックを利用して死活監視も行うことができます。

fucntionで/healthzなどの任意のパスを追加して、アクセスすると200ステータスを返すエンドポイントを追加します。

コンソールから[monitoring] > [検出] > [稼動時間チェック] > [+稼動時間チェックを作成]で作成画面へ

上記画像のように設定すると、functionsで設定したhttps://xx-xx-xx.com/healthzに対して3リージョンからそれぞれ1分毎にhttps://xx-xx-xx.com/healthzが利用可能かアクセスします。([レスポンスの検証]で実際に/healthzが利用できるか確認できます。

稼動時間チェック作成時にはアラートポリシーも作成可能で、どこか1リージョンでも失敗したら発報して登録している検知先にお知らせ、という形で監視設定を盛り込むこともできます。

ちなみに稼動時間チェックの費用については、1プロジェクトにつき月間100万回リクエストまで無料なので、上記設定で稼動時間チェックを作ると

3check/min * 60min * 24hour * 30Days = 129,600check

となるので無料枠の中におさまります。

終わりに

以上のように設定することで、Cloud Run FunctionsにおいてもIngressのIP制限やEgressの固定IPによる外部通信が設定可能です。

Terraform によるリソース管理を行うことで再現性と保守性も確保しつつ柔軟なインフラ設計が可能になりますので、これからの Serverless インフラ設計の参考になれば幸いです。引き続きよろしくお願いします。tokuraでした。


採用情報
お問い合わせ