はじめに
Cloud Run で動かすアプリを、特定のグループのメンバーだけがブラウザで開ける状態にしたいと考えました。そこで、ロードバランサーを使わずに Cloud Run へ直接 IAP を設定し、Terraform で構成しました。
IAP(Identity-Aware Proxy)は、アプリの手前で Google アカウントのログインとアクセス権を確認する Google Cloud の機能です。本記事では、Cloud Run に IAP 認証をかける Terraform の書き方と、実際に試した動作確認の結果をまとめます。
本記事のまとめ
- Cloud Run Service に
iap_enabled = trueを付け、2 つの IAM を付与するだけで、ロードバランサーなしに IAP 認証をかけられる。 - 組織配下のプロジェクトなら、OAuth クライアントを自分で作らなくても Google 管理の OAuth クライアントで動くことを実機で確認した。
- 許可していないユーザーは、Google のログインは通ったうえで IAP の拒否ページになる。
roles/ownerを持っていても IAP 経由では開けない。閲覧させたい人にはroles/iap.httpsResourceAccessorを明示的に付ける。

Cloud Run の IAP 認証とは(ロードバランサー不要)
Cloud Run の IAP 認証は、ロードバランサーを立てずに Cloud Run Service へ直接設定できます。直接 IAP が使えるようになる前は、ロードバランサーを経由して IAP を設定する必要がありました。
Cloud Run に直接 IAP を設定する機能は、Cloud Run のリリースノートで 2026 年 3 月 13 日に一般提供(GA)になったと告知されています。設定方法は公式ドキュメント「Configure IAP for Cloud Run」にまとまっています。
直接 IAP の構成で、利用者がアプリを開くまでの流れは次のとおりです。
- 利用者がブラウザで Cloud Run の URL を開くと、IAP が Google アカウントのログインを求める。
- ログイン後、IAP は IAM でアクセス権を確認する。権限が無ければ拒否ページを返す。
- 権限があれば、IAP が利用者に代わって Cloud Run を呼び出し、アプリの画面が表示される。
なお、IAP でログインに使える ID の種類(認証ソース)は、1 つのサービスにつき 1 つだけです。Google アカウントと、Microsoft Entra ID などの外部 ID を、1 つのサービスで両方は許可できません。本記事は Google アカウントを使う構成を扱います。
外部 ID を使う場合は IAP の設定 API で Cloud Run 用のリソースを指定しますが、この部分は 2026 年 9 月の検証時点でまだプレビュー版の扱いでした。Google アカウントだけで使う本記事の構成では、この API は使いません。
設定の前提(OAuth クライアント・権限・provider)
設定の前に、OAuth クライアント・デプロイする人の権限・Terraform の provider の 3 点を確認します。組織配下のプロジェクトであれば、OAuth クライアントを自分で用意する必要はありません。
OAuth クライアントは Google 管理のもので足りる
OAuth クライアントは、IAP が Google のログイン画面を出すときに使う「アプリの登録情報」です。IAP を有効にすると、既定では Google が管理する OAuth クライアントが使われます。
ただし公式ドキュメントによると、Google 管理の OAuth クライアントで開けるのは、リソースと同じ組織に属するユーザーだけです。組織外のユーザーにも見せる場合は、独自の OAuth クライアントの設定が必要になります。
私の検証環境は Google Cloud の組織配下にあるプロジェクトで、OAuth クライアントを 1 つも作らずに IAP 認証が動きました。組織に属していないプロジェクトについては、今回は検証していません。

デプロイする人に必要なロール
公式ドキュメントでは、IAP を有効化する人に次のロールが必要とされています。Terraform を CI で実行するなら、そのサービスアカウントに付けておきます。
| ロール | 用途 |
|---|---|
roles/run.admin | Cloud Run Service の作成・更新 |
roles/iap.admin | IAP のアクセス権(IAM)の設定 |
roles/iap.settingsAdmin | IAP の設定 |
roles/oauthconfig.editor | OAuth の構成 |
roles/iam.serviceAccountUser | Cloud Run に実行用サービスアカウントを割り当てる |
roles/artifactregistry.reader | コンテナイメージの読み取り |
Terraform は google-beta provider を指定する
私の環境では google provider が 5.x 系に固定されていました。そこで google-beta provider を 7.x 系で追加し、IAP 関連のリソースにだけ provider = google-beta を付けて動かしました。この方法なら terraform validate が通り、google provider のメジャーバージョンを上げずに済みます。
provider の定義は次のように、google と google-beta を並べて書きます。
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = "~> 7.0"
}
}
}
provider "google" {
project = var.project_id
region = var.region
}
provider "google-beta" {
project = var.project_id
region = var.region
}google-beta で作りたいリソースには、次の節のコードのように provider = google-beta を 1 行足します。書いていないリソースは、これまでどおり google provider で作られます。provider を追加・変更したら、terraform init -upgrade でロックファイル(.terraform.lock.hcl)を更新してから plan してください。
Terraform で Cloud Run に IAP 認証を設定する手順
必要なリソースは、Cloud Run Service、IAP サービスエージェントの実行権限、閲覧者のアクセス権の 3 つです。以下は私が書いた定義をもとにした最小構成の例で、プロジェクト ID やグループのアドレスはご自身の環境に置き換えてください。
Cloud Run Service で iap_enabled を有効にする
Cloud Run Service に iap_enabled = true を書くと、その Service で IAP が有効になります。動作確認には Google 提供のサンプルイメージを使いました。実行用のサービスアカウント(google_service_account.app)の定義は省略しているので、別途作成してください。
resource "google_cloud_run_v2_service" "app" {
provider = google-beta
project = var.project_id
name = "cloudrun-iap-sample"
location = "asia-northeast1"
ingress = "INGRESS_TRAFFIC_ALL"
iap_enabled = true
template {
service_account = google_service_account.app.email
scaling {
min_instance_count = 0
}
containers {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}ingress は外部からのアクセスを受け付ける INGRESS_TRAFFIC_ALL にしています。アクセスを絞るのは IAP の役割なので、allUsers に roles/run.invoker は付けていません。
IAP サービスエージェントに Cloud Run の実行権限を付ける
サービスエージェントは、Google Cloud のサービスが利用者のプロジェクトで処理を行うために使う、Google 管理のサービスアカウントです。IAP のサービスエージェントは service-プロジェクト番号@gcp-sa-iap.iam.gserviceaccount.com です。これに roles/run.invoker を付けると、IAP が Cloud Run を呼び出せるようになります。
resource "google_project_service_identity" "iap_service_agent" {
provider = google-beta
project = var.project_id
service = "iap.googleapis.com"
}
resource "google_cloud_run_v2_service_iam_member" "iap_invoker" {
project = var.project_id
location = google_cloud_run_v2_service.app.location
name = google_cloud_run_v2_service.app.name
role = "roles/run.invoker"
member = "serviceAccount:${google_project_service_identity.iap_service_agent.email}"
}サービスエージェントのメールアドレスは、プロジェクト番号を文字列でつなげて組み立てず、google_project_service_identity の email を参照しています。
閲覧させるグループに roles/iap.httpsResourceAccessor を付ける
アプリを開ける人は、roles/iap.httpsResourceAccessor で決まります。私の環境では、IAM は個人ではなくグループ単位で付ける方針です。そのため Google グループに付与しました。
resource "google_iap_web_cloud_run_service_iam_binding" "iap_access" {
provider = google-beta
project = var.project_id
location = google_cloud_run_v2_service.app.location
cloud_run_service_name = google_cloud_run_v2_service.app.name
role = "roles/iap.httpsResourceAccessor"
members = [
"group:app-users@example.com",
]
}_iam_binding は、そのロールを持つメンバーを Terraform の定義どおりに上書きします。コンソールで手動追加したメンバーは apply で消えるので、plan で既存のメンバーを必ず確認してください。ほかの付与と共存させたい場合は _iam_member を使います。

plan で差分を確認して apply する
定義を書いたら、フォーマット・構文・差分の順に確認します。追加だけで、削除や置き換えが出ていないことを見てから apply します。
terraform fmt -check -diff
terraform validate
terraform plan動作確認:許可したユーザーだけが開ける
apply 後、許可したグループのユーザーと、グループ外のユーザーの 2 人で Cloud Run の URL を開きました。グループのユーザーだけがアプリを開け、グループ外のユーザーは IAP の拒否ページで止まりました。
グループのユーザーで開くと、Google のログインを経てサンプルページが表示されます。サンプルイメージは IAP が渡した ID を画面に出すため、次のようにどのアカウントで入ったかが分かります。
You are authenticated as accounts.google.com:<ログインしたアカウント>
この表示があれば、IAP の認証を通ってアプリに届いたことを確かめられます。疎通確認のためだけに自前のアプリを用意する必要はありません。
一方、グループに入っていないユーザーで同じ URL を開くと、IAP の「You don’t have access」というページが表示され、アプリには届きません。

確認した内容をまとめると次のとおりです。
| 確認したこと | 結果 |
|---|---|
| 許可したグループのユーザーが開ける | 開けた |
| グループ外のユーザーは拒否される | IAP の拒否ページになった |
| OAuth クライアントを作らずに動く | 動いた(Google 管理の OAuth クライアントのみ) |
asia-northeast1 で動く | 動いた |
リージョンについては、公式ドキュメントに直接 IAP のリージョン制限の記述が見つかりませんでした。東京リージョン(asia-northeast1)で動くことは、今回の検証で確認しています。
つまずきやすい点
検証中に判断を誤りかけた点が 2 つありました。とくに「owner なら開けるはず」という思い込みは、権限の中身を確かめると誤りだと分かります。
拒否ページはログインの失敗ではない
拒否ページには、ログインしたユーザーのアカウントが表示されていました。つまり、Google のログイン(認証)は成功しており、そのうえで IAP がアクセス権(認可)を確認して拒否しています。
拒否ページが出たら、ログインをやり直すのではなく、そのユーザーに roles/iap.httpsResourceAccessor が付いているかを確認します。
roles/owner では IAP 経由で開けない
検証に使ったグループのユーザーはプロジェクトの roles/owner も持っていたため、「アクセス権を付けなくても開けたのでは」と疑いました。そこでロールに含まれる権限を調べました。
gcloud iam roles describe roles/owner --format="value(includedPermissions)" \
| tr ';' '\n' | grep accessViaIAProles/owner に含まれる accessViaIAP 系の権限は、次の 2 つだけでした。どちらも TCP 転送(VM への接続など)用で、Web アプリを開くための権限ではありません。
iap.tunnelDestGroups.accessViaIAP
iap.tunnelInstances.accessViaIAP
IAP 経由で Web アプリを開くには iap.webServiceVersions.accessViaIAP が必要です。roles/iap.httpsResourceAccessor の中身は、この 1 権限だけです。プロジェクトの owner でも、このロールを付けなければ開けません。
なお、--format="value(includedPermissions)" の出力は ; 区切りです。, で分割すると権限が 1 つも見つからず、誤った結論になるので注意してください。
まとめ
Cloud Run に直接 IAP を設定し、ロードバランサーなしで Google アカウントの IAP 認証をかけられることを確認しました。必要なのは iap_enabled = true と、IAP サービスエージェントへの実行権限、閲覧者へのアクセス権の 3 つです。
- 組織配下のプロジェクトなら、OAuth クライアントは Google 管理のもので足りる。ただし開けるのは組織内のユーザーだけになる。
- 閲覧させたい人には
roles/iap.httpsResourceAccessorを付ける。roles/ownerでは開けない。 - 拒否ページが出たら、ログインではなくアクセス権を確認する。
まずはサンプルイメージで IAP 認証を通し、アクセス権の付け方を確かめてから自分のアプリに切り替えるのがおすすめです。Terraform の各リソースの引数は、Terraform Registry の google_cloud_run_v2_service で確認できます。
