IP制限したClour Runサービスをterraformで構築してみた
はじめに
この記事では、Terraform を使用して Google Cloud Run にサンプルコンテナの hello アプリケーションをデプロイする方法をご紹介します。基本的には、こちらの記事の内容を参考にしていますが、サンプルコンテナを使うことで、よりシンプルかつ手軽に Terraform を動かせるように工夫しています。
Cloud Run と Terraform を組み合わせることで、インフラストラクチャのコード化やデプロイの自動化が可能になります。この記事を通じて、その基本的な手順とポイントを解説します。
全体のコードはこちらに置いています:
※本番環境で使用する場合は、Cloud IAMの認証などの設定も適切に行い、セキュリティには十分注意してください。
TL;DR
- 目的: Terraform を使って Cloud Run にサンプルの hello アプリケーションをデプロイし、ロードバランサと Cloud Armor でアクセス制御を設定します
-
手順の概要:
- Terraform ファイルを準備し、サンプルコンテナの hello アプリケーションを指定
- Cloud Armor ポリシーに自分のグローバル IP アドレスを設定してアクセスを制限
- Terraform コマンド (
terraform init
,terraform plan
,terraform apply
) を実行してリソースを作成 - 作成されたロードバランサの IP アドレスにアクセスしてデプロイを確認
-
注意点:
- ロードバランサや Cloud Armor の反映には時間がかかる場合があります
- 利用後は
terraform destroy
でリソースをクリーンアップします
この記事を読むことで、Terraform を使った Cloud Run サービスのデプロイ方法と、基本的なIPアクセス制御の設定方法を理解できます。
構成図
構成図を書くと以下のような形になるかと思います。
terraform設定
基本的には以下の記事の内容を参考に構築しています。
変更点として、サンプルコンテナのhelloアプリケーションを使用することで、より簡単にterraformを動かせるようにしてみました。
また、terraform を使って GCP にロードバランサを設置する方法は以下の記事が参考になりました。
今回は設定していないですが、HTTPS化する方法についても解説してあります。サンプルコンテナのhelloアプリケーションをCloud Runに設定する
cloud runサービスにデプロイするアプリケーションとして、 サンプルコンテナのhelloアプリケーションをimageに設定しました。
image = "us-docker.pkg.dev/cloudrun/container/hello:latest"
また、terraform destroy時に削除できるようにするために、deletion_protection = false
にしています。
# Cloud Run サービス
resource "google_cloud_run_v2_service" "hello_cloud_run" {
name = "hello"
location = var.region
description = "cloud run service"
ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER" # 内部ロードバランサーからのトラフィックのみを許可します
template {
containers {
name = "hello"
image = "us-docker.pkg.dev/cloudrun/container/hello:latest"
resources {
cpu_idle = false
}
}
scaling {
min_instance_count = 0
max_instance_count = 1
}
}
traffic {
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" # 最新のリビジョン(デプロイメント)にトラフィックを送信することを指定
percent = 100
}
deletion_protection = false # 削除保護を無効にする (terraform destroy時に削除できるようにする)
}
許可するIPアドレスの設定
変更が必要な箇所としては、cloud armor policyのsrc_ip_rangesに自宅のグローバルIPを設定することです。
# Load Balancerのcloud armor policy
resource "google_compute_security_policy" "hello_policy" {
name = "inference-policy"
description = "Load Balancer用のcloud armor policy"
rule {
action = "allow"
priority = 1000
match {
versioned_expr = "SRC_IPS_V1"
config {
# FIXME: your ip address
src_ip_ranges = ["YOUR_IP_ADDRESS"]
}
}
description = "my home global ip address"
}
rule {
action = "deny(403)"
priority = 2147483647
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
}
adaptive_protection_config {
layer_7_ddos_defense_config {
enable = true
}
}
}
自宅のPCのグローバルIPの調べ方は以下を参照しました。(mac)
terraform全体
terraformファイル全体をここに載せておきます。
terraformファイル全体
provider "google" {
project = var.project
region = var.region
}
variable "project" {
description = "The ID of the project in which resources will be managed."
type = string
}
variable "region" {
description = "The region in which resources will be created."
type = string
}
output "load_balancer_ip" {
value = google_compute_global_address.hello_lb_ip.address
description = "ロードバランサーの静的IPアドレス"
}
# load balancer用の静的IP
resource "google_compute_global_address" "hello_lb_ip" {
name = "hello-lb-ip"
description = "load balancerの静的IP"
address_type = "EXTERNAL"
ip_version = "IPV4"
project = var.project
}
# Cloud Run サービス
resource "google_cloud_run_v2_service" "hello_cloud_run" {
name = "hello"
location = var.region
description = "cloud run service"
ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER" # 内部ロードバランサーからのトラフィックのみを許可します
template {
containers {
name = "hello"
image = "us-docker.pkg.dev/cloudrun/container/hello:latest"
resources {
cpu_idle = false
}
}
scaling {
min_instance_count = 0
max_instance_count = 1
}
}
traffic {
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST" # 最新のリビジョン(デプロイメント)にトラフィックを送信することを指定
percent = 100
}
deletion_protection = false # 削除保護を無効にする (terraform destroy時に削除できるようにする)
}
# Cloud Runの未認証呼び出し許可policy (本番環境ではmembersに適切な値を設定すること)
data "google_iam_policy" "noauth" {
binding {
role = "roles/run.invoker"
members = [
"allUsers",
]
}
}
# Cloud Runの未認証呼び出し許可を付与
resource "google_cloud_run_service_iam_policy" "noauth" {
location = google_cloud_run_v2_service.hello_cloud_run.location
project = var.project
service = google_cloud_run_v2_service.hello_cloud_run.name
policy_data = data.google_iam_policy.noauth.policy_data
}
# Load Balancerのserverless NEG
resource "google_compute_region_network_endpoint_group" "hello_neg" {
name = "hello-neg"
network_endpoint_type = "SERVERLESS"
region = "asia-northeast1"
# cloud runのserviceを指定
cloud_run {
service = google_cloud_run_v2_service.hello_cloud_run.name
}
}
# Load Balancerのcloud armor policy
resource "google_compute_security_policy" "hello_policy" {
name = "hello-policy"
description = "Load Balancer用のcloud armor policy"
rule {
action = "allow"
priority = 1000
match {
versioned_expr = "SRC_IPS_V1"
config {
# FIXME: your ip address
src_ip_ranges = ["YOUR_IP_ADDRESS"]
}
}
description = "my home global ip address"
}
rule {
action = "deny(403)"
priority = 2147483647
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
}
adaptive_protection_config {
layer_7_ddos_defense_config {
enable = true
}
}
}
# load balancerのbackend service
resource "google_compute_backend_service" "hello_backend_service" {
name = "hello-backend-service"
protocol = "HTTP"
port_name = "http"
timeout_sec = 30
load_balancing_scheme = "EXTERNAL_MANAGED"
# cloud armor policyを指定
security_policy = google_compute_security_policy.hello_policy.id
backend {
group = google_compute_region_network_endpoint_group.hello_neg.self_link
}
}
# url map
resource "google_compute_url_map" "hello_url_map" {
name = "hello-lb"
description = "load balancer用のlb"
default_service = google_compute_backend_service.hello_backend_service.id
path_matcher {
name = "hello-apps"
default_service = google_compute_backend_service.hello_backend_service.id
}
}
resource "google_compute_target_http_proxy" "hello_target_http_proxy" {
name = "predictor-target-http-proxy"
url_map = google_compute_url_map.hello_url_map.id
}
# フロントエンドの設定(http)
resource "google_compute_global_forwarding_rule" "hello_forwarding_rule_http" {
name = "hello-forwarding-rule-http"
description = "load balancerのforwarding rule(http)"
load_balancing_scheme = "EXTERNAL_MANAGED"
target = google_compute_target_http_proxy.hello_target_http_proxy.id
ip_address = google_compute_global_address.hello_lb_ip.address
ip_protocol = "TCP"
port_range = "80"
}
terraform実行
cd infra
terraform init
terraform plan
terraform apply
terraform planやterraform applyでvariablesの入力を求められるので、適切に入力します。
$ terraform plan
var.project
The ID of the project in which resources will be managed.
Enter a value:
※ロードバランサやCloud Armorの反映に少し時間がかかることがあります。
アクセス
作成されたIPにアクセスします。
$ terraform output
load_balancer_ip = {IP_ADDRESS}
http://{IP_ADDRESS} にアクセス
以下の画面が出てきたら成功です!
クリーンアップ
Terraformで作成したリソースをすべて削除して、環境をクリーンな状態に戻すには、以下のコマンドを実行します。
terraform destroy
Discussion