GCP Cloud Runの未認証アクセスを防ぐためのIAM認証設定について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、gcloud CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、Cloud Runサービスの認証要件を設定し未認証アクセスを防止する手順について、リスクと対策を解説します。

ポリシーの説明
Cloud Runサービスで認証を必須とし、Cloud IAMによるアクセス制御を強制することで、未認証アクセスを防止します。
Cloud Runサービスがデフォルトで「すべてのユーザー」に公開されている場合、インターネット上の誰でもサービスにアクセスできる状態となります。これは、機密性の高いAPIやマイクロサービスにとって重大なセキュリティリスクとなります。IAM認証を有効にすることで、認証されたユーザーやサービスアカウントのみがアクセスできるよう制限し、セキュリティを強化できます。
修復方法
コンソールでの修復手順
Google Cloud コンソールを使用して、Cloud Runサービスへのアクセスを認証済みユーザーのみに制限します。
- Google Cloud Consoleにログインし、Cloud Runページに移動します。
- 対象のCloud Runサービスをクリックして詳細ページを開きます。
- トリガータブをクリックします。
- 認証セクションで、現在の設定を確認します。
- 編集をクリックして、認証設定を変更します。
- 認証が必要を選択します。

- 保存をクリックして変更を適用します。
Terraformでの修復手順
Cloud Runサービスで認証を必須とし、特定のユーザーのみにアクセスを許可するTerraformコードと、主要な修正ポイントを説明します。
# -------------------- ① サービスアカウント --------------------
resource "google_service_account" "cloudrun_sa" {
account_id = "cloudrun-service-${var.environment}"
display_name = "Cloud Run Service Account"
description = "Service account for Cloud Run service"
}
# -------------------- ② Cloud Runサービス --------------------
resource "google_cloud_run_service" "main" {
name = "secure-service-${var.environment}"
location = var.region
template {
spec {
# サービスアカウントを指定
service_account_name = google_service_account.cloudrun_sa.email
containers {
image = "gcr.io/${var.project_id}/${var.image_name}:${var.image_tag}"
# 環境変数
env {
name = "ENVIRONMENT"
value = var.environment
}
# リソース制限
resources {
limits = {
cpu = "1"
memory = "512Mi"
}
}
# ヘルスチェック用のプローブ
startup_probe {
http_get {
path = "/health"
}
initial_delay_seconds = 0
period_seconds = 10
timeout_seconds = 1
failure_threshold = 3
}
}
# 最大同時実行数
container_concurrency = 100
}
metadata {
annotations = {
# 自動スケーリングの設定
"autoscaling.knative.dev/minScale" = "1"
"autoscaling.knative.dev/maxScale" = "100"
# VPCコネクタ(プライベートリソースへのアクセスが必要な場合)
"run.googleapis.com/vpc-access-connector" = google_vpc_access_connector.connector[0].id
"run.googleapis.com/vpc-access-egress" = "private-ranges-only"
}
}
}
traffic {
percent = 100
latest_revision = true
}
depends_on = [google_project_service.run]
}
# -------------------- ③ IAM設定(認証を必須化) --------------------
# デフォルトではパブリックアクセスが許可されている可能性があるため、
# google_cloud_run_service_iam_policyを使用して明示的にポリシーを設定
# IAMポリシーデータ
data "google_iam_policy" "noauth" {
binding {
role = "roles/run.invoker"
members = concat(
[for user in var.authorized_users : "user:${user}"],
[for sa in var.authorized_service_accounts : "serviceAccount:${sa}"]
)
}
}
# Cloud RunサービスのIAMポリシーを設定
resource "google_cloud_run_service_iam_policy" "policy" {
location = google_cloud_run_service.main.location
service = google_cloud_run_service.main.name
policy_data = data.google_iam_policy.noauth.policy_data
}
# -------------------- ④ VPCコネクタ(オプション) --------------------
resource "google_vpc_access_connector" "connector" {
count = var.enable_vpc_connector ? 1 : 0
name = "cloudrun-connector-${var.environment}"
region = var.region
network = var.vpc_network_name
ip_cidr_range = var.vpc_connector_cidr
min_instances = 2
max_instances = 10
}
# -------------------- ⑤ 変数定義 --------------------
variable "authorized_users" {
description = "List of user emails authorized to invoke the service"
type = list(string)
default = []
}
variable "authorized_service_accounts" {
description = "List of service account emails authorized to invoke the service"
type = list(string)
default = []
}
variable "enable_vpc_connector" {
description = "Enable VPC connector for private resource access"
type = bool
default = false
}
# -------------------- ⑥ 出力 --------------------
output "service_url" {
value = google_cloud_run_service.main.status[0].url
description = "The URL of the Cloud Run service"
}
output "service_account_email" {
value = google_service_account.cloudrun_sa.email
description = "The email of the service account used by Cloud Run"
}
主要な修正ポイント
- 認証の必須化:
google_cloud_run_service_iam_policy
を使用して明示的にポリシーを設定し、未認証アクセスを完全に拒否 - 明示的な権限付与: 特定のユーザーとサービスアカウントのみに
roles/run.invoker
ロールを付与 - 専用サービスアカウント: デフォルトサービスアカウントの代わりに専用のサービスアカウントを使用
- VPCコネクタ: 必要に応じてプライベートリソースへの安全なアクセスを設定
- ヘルスチェック: startup_probeを設定してサービスの健全性を監視
重要な考慮事項
- 既存サービスの移行: パブリックアクセスから認証必須への変更時は、事前にクライアントアプリケーションの認証実装を確認
- サービスアカウントの管理: サービス間通信には専用のサービスアカウントを使用し、最小権限の原則を遵守
- モニタリング: 認証失敗の監視を設定し、不正アクセス試行を検出
認証されたCloud Runサービスの呼び出し方法
認証が必須のCloud Runサービスを呼び出すには、IDトークンを含める必要があります:
サービスアカウントからの呼び出し
# IDトークンを取得(サービスアカウントの認証情報を使用)
TOKEN=$(gcloud auth print-identity-token \
--audiences=https://[SERVICE_URL])
# トークンを使用してサービスを呼び出し
curl -H "Authorization: Bearer $TOKEN" \
https://[SERVICE_URL]
# サービスアカウントのキーを使用する場合
gcloud auth activate-service-account --key-file=[KEY_FILE]
TOKEN=$(gcloud auth print-identity-token \
--audiences=https://[SERVICE_URL])
アプリケーションからの呼び出し(Pythonの例)
import google.auth.transport.requests
import google.oauth2.id_token
import requests
# IDトークンを取得
auth_req = google.auth.transport.requests.Request()
target_audience = "https://[SERVICE_URL]"
id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_audience)
# リクエストを送信
headers = {"Authorization": f"Bearer {id_token}"}
response = requests.get(target_audience, headers=headers)
まとめ
GCP Cloud Runサービスの認証要件を適切に設定することは、インターネットに公開されるサービスのセキュリティを確保する上で不可欠です。本記事で紹介した手順により、未認証アクセスを防ぎ、DDoS攻撃やデータ漏洩のリスクを大幅に低減できます。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。