こんにちは、博報堂テクノロジーズの木村です。
この記事では、Google CloudのCloud RunにてGoogle Workspace組織外のユーザーに対して、Identity-Aware Proxy(IAP)を利用した認証機能を利用する方法について解説します。
各構成要素と課題
この章では各構成要素の解説と、この構成で直面した課題について説明します。
Cloud Run
Cloud Run は、コンテナイメージをそのままデプロイできるサーバーレスなコンテナ実行基盤です。
Cloud Run単独では認証の機能を持たないため、アプリケーション側で実装するか、手前に認証の仕組みを置く必要があります。
Identity-Aware Proxy
Identity-Aware Proxy(IAP)は、アプリケーションの手前に立ち、認証認可処理を代行してくれるマネージドサービスです。アプリケーション側に認証コードを一切書かずに認証処理を実装することができます。
また、IAP では Access Context Manager(ACM)のアクセスレベルを利用することができます。アクセスレベルには接続元 IP レンジなどの条件を定義できるため、「許可されたメンバーが、特定のIPアドレスからアクセスした場合のみ許可する」といった制御もIAPでのみ実現することが可能です。
一方で従来の IAP は、LBのバックエンドサービスに対して有効化する方式が前提でした。そのため、グローバル IP・SSL証明書・DNS レコード・URLマップ・サーバーレスNEGといった ロードバランサー関連のリソースを全て構築する必要がありました。
Cloud RunへのIAPの直接設定
これに対し、2026年3月よりCloud Runへ直接IAPを適用する方式がGAされました。Terraform では、Cloud Runのリソースに1行追加するだけで利用可能です。
resource "google_cloud_run_v2_service" "main" {
name = "test-run-iap"
...
# LBを挟まずCloud Runへ直接IAPを割り当てる
iap_enabled = true
...
}
LBを利用しない構成となるため、社内向けのアプリケーションなどで、独自ドメインとWAFが不要で、認証とIP制限さえあればよいという要件に向いた構成となります。この構成をとることで、LBの構築と運用が不要となり、メンテナンスコストを下げて運用することが可能です。
課題
このように要件次第では便利なCloud Runへ直接IAPを設定する機能ですが、構築を進める中で組織外ユーザーのログインに失敗するという事象にあたりました。
これは、IAPはデフォルトでGoogleが管理するOAuth設定を用いて動作するためです。組織外のアカウントにIAM上でロールを付与してもログインできず、プロジェクトが属する組織内ユーザーしかログインできません。
これを解消するには、External(外部)のOAuth同意画面を持つカスタムOAuthクライアントを作成し、それを IAPに適用する必要があります。しかし、Cloud Runに直接IAPを設定する機能はGAされて日が経っておらずノウハウがまとまっていなかったため、今回はこの部分を中心に解説します。
設定手順
全体の流れは次のとおりです。ステップ1で必要なリソースをTerraformで構築した上で、ステップ2以降は手動手順にてOAuth周りの設定を実施します。
- TerraformでCloud Run+IAP+ACMを構築する
- OAuth同意画面をExternalで作成する
- 公開ステータスを設定する
- OAuthクライアントを作成し、リダイレクトURIを設定する
- カスタムOAuthクライアントをIAPに適用する
1. TerraformでCloud Run+IAP+ACMを構築する
まず、Cloud Run、IAP、ACMを構築します。なお、Cloud RunとIAPのAPIは有効化済みであることを前提に進めます。
ACMのアクセスレベルを作成する
以下の通り、ACMのアクセスレベルを作成します。なお、このACMのリソースのみ組織単位での作成となるため、組織レベルの権限が必要となります。
# 組織単位のアクセスポリシー。1組織につき1つしか作成できないため、
# 既存のポリシーがある場合はこのリソースを作らず、そのpolicy_idを参照する。
resource "google_access_context_manager_access_policy" "org" {
parent = "organizations/<組織ID>"
title = "default policy"
}
resource "google_access_context_manager_access_level" "ip_restricted" {
parent = "accessPolicies/${google_access_context_manager_access_policy.org.name}"
name = "accessPolicies/${google_access_context_manager_access_policy.org.name}/accessLevels/iprestricted"
title = "iprestricted"
basic {
conditions {
# 許可する接続元IPレンジ
ip_subnetworks = [
"XX.XX.XX.XX/24",
]
}
}
}
Cloud Runを作成する
以下の通り Cloud Runを作成します。LBを挟まずアクセスを受け付けるため、 ingress は INGRESS_TRAFFIC_ALL とし、 iap_enabled を true に設定します。
locals {
project = "test-project"
location = "asia-northeast1"
}
resource "google_cloud_run_v2_service" "main" {
project = local.project
location = local.location
name = "direct-iap-test-run"
# LBを挟まないためIngressは全てのネットワークから受け付ける
# IAPにてIP制限を実施する
ingress = "INGRESS_TRAFFIC_ALL"
# LBを挟まずCloud Runへ直接IAPを割り当てる
iap_enabled = true
template {
containers {
# テストコンテナ
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
IAPに呼び出し権限を与える
IAPからCloud Runへの実際の呼び出しは、Google管理のサービスアカウントにて行われます。したがってCLoud Runの呼び出し権限である roles/run.invoker はこのサービスアカウントに付与します。
data "google_project" "this" {
project_id = var.project_id
}
locals {
project = "test-project"
location = "asia-northeast1"
# Google管理のサービスアカウント。iap.googleapis.com有効化時にGCPが自動作成する。
iap_service_agent_email = "service-${data.google_project.this.number}@gcp-sa-iap.iam.gserviceaccount.com"
}
# run.invokerを付与する。
resource "google_cloud_run_v2_service_iam_member" "iap_invoker" {
project = local.project
location = local.location
name = google_cloud_run_v2_service.main.name
role = "roles/run.invoker"
member = "serviceAccount:${local.iap_service_agent_email}"
}
アクセス許可とIP制限を設定する
アクセスを行うユーザーに対して roles/iap.httpsResourceAccessor を付与し、IAM Conditions で ACM のアクセスレベルを要求します。
locals {
# ダッシュボードの利用者、ユーザーでもグループでも適用可
iap_members = [
"user:test-user@example.com"
"group:test-grou@example.com",
]
# IAPのIP制限に用いるACMアクセスレベル。組織レベルで作成済みのものを設定する。
access_levels = [
"accessPolicies/<ポリシーID>/accessLevels/iprestricted",
]
}
resource "google_iap_web_cloud_run_service_iam_member" "accessor" {
for_each = toset(local.iap_members)
project = local.project
location = local.location
cloud_run_service_name = google_cloud_run_v2_service.main.name
role = "roles/iap.httpsResourceAccessor"
member = each.value
# IAMコンディションでACMアクセスレベルを要求する
condition {
title = "access-level-restriction"
description = "許可されたAccess Context Managerアクセスレベルからのアクセスのみを許可する"
expression = join(" || ", [for level in local.access_levels : "\"${level}\" in request.auth.access_levels"])
}
}
動作確認
ここまでの手順を実施すると組織内のユーザーの場合はアクセス可能になりますが、組織外のユーザーの場合はアクセスが拒否されることが分かります。
2. OAuth同意画面をExternalで作成する
対象プロジェクトのコンソールから Google Auth Platform → ブランディング を開き、開始 から以下を入力します。
- アプリ名:
<アプリ名> - ユーザーサポートメール:担当者のメールアドレス
- 対象(Audience):
External(外部) - デベロッパーの連絡先メール:担当者のメールアドレス
対象を External にすることで、組織外ユーザーを許可することが可能になります。
なお、「OAuthブランドは1プロジェクトにつき1つ」しか作成できません。同一プロジェクト内の他の機能がOAuth同意画面を利用している場合は共用することになるため、アプリ名などを事前に調整する必要があります。
3. 公開ステータスを設定する
Externalの同意画面を作成後の テスト 状態から 本番 に切り替えます。
なお、本番に設定することでOAuth同意画面に全てのユーザーが到達できるようになりますが、ログイン自体ができても、IAMで許可されていなければ403となり、アプリケーションには到達できません。
4. OAuthクライアントを作成し、リダイレクトURIを設定する
Google Auth Platform → クライアント から クライアントを作成 を選び、以下を入力します。
- アプリケーションの種類:
ウェブアプリケーション - 名前:
<アプリ名>
作成後に表示されるクライアントIDとクライアントシークレットを控えておきます。
続いて、作成したクライアントを再度編集し、承認済みのリダイレクトURIに以下を追加します。
<https://iap.googleapis.com/v1/oauth/clientIds/><クライアントID>:handleRedirect
リダイレクト URI に自身のクライアント ID を含める必要があるため、一度OAuthクライアントを作成してから、もう一度編集して設定するという順序になります。
5. カスタムOAuthクライアントをIAPに適用する
最後に、作成した OAuthクライアントをIAPに紐付けます。この操作はコンソールではなく gcloud コマンドで行います。--resource-type=cloud-run を設定することで、Cloud Runに対するIAPの設定ができます。
cat << EOF > iap-oauth.yaml
accessSettings:
oauthSettings:
clientId: <クライアントID>
clientSecret: <クライアントシークレット>
EOF
gcloud beta iap settings set iap-oauth.yaml \
--project=<プロジェクトID> \
--resource-type=cloud-run \
--region=asia-northeast1 \
--service=<Cloud Runのサービス名>
動作確認
ここまでの手順を実施すると組織外のユーザーについてもログインできるようになります。
まとめ
本記事では、Cloud Runに対してLBを介さず直接IAPを適用する構成と、組織外ユーザーにアクセスを許可するための手順を解説しました。
「認証とIP制限さえあればよい」という要件であれば、今回紹介した直接IAPを適用する設定は維持・メンテナンスコストを下げることができる構成となります。
同様の構成を検討されている方の参考になれば幸いです。

