🧑‍🚀

Cloud Run で Workforce Identity と IAP を利用して Microsoft Entra アカウントで認証する

2024/05/27に公開

はじめに

こんにちは!クラウドエースの SRE 部に所属している小田です。
今回は、Microsoft Entra テナント(旧 Azure AD)を外部 Identify Provider(以下、IdP)として Workforce Identity 連携を行い、Microsoft Entra アカウントで Cloud Run のアプリケーションに Identity-Aware Proxy(以下、IAP)認証を行う方法についてのご紹介です。

2024 年 5 月 6 日にプレビューとなったばかりの機能で、私自身とても気になっていたので試してみました。

対象読者

  • Microsoft Entra アカウントで IAP 認証を行いたい人
  • Workforce Identity で Microsoft Entra テナントと連携したい人

何が嬉しいのか

従来、IAP で外部の IdP ユーザーで認証を行いたい場合、Identity Platform を利用する構成が一般的でしたが、ログインページ等を用意する必要があったりしました。
また、IAP 単体の場合は Google Workspace または Cloud Identity に外部 IdP ユーザーを連携し、Google アカウントとしてログインする必要がありました。

しかし、Workforce Identity 連携が IAP で利用できるようになったことで、前者のようにログインページ等を用意する必要はなくなり、後者のように Google Workspace または Cloud Identity に外部 IdP ユーザーが連携されないため、ユーザー ディレクトリが汚れないというメリットがあります。

Workforce Identity とは

Workforce Identity は Microsoft Entra や Okta など外部の IdP を利用して認証・認可を行い、Google Cloud のリソースにアクセスできるサービスです。

OpenID Connect(以下、OIDC)または Security Assertion Markup Language(以下、SAML)プロトコルをサポートしている外部 IdP と連携することができます。
https://cloud.google.com/iam/docs/workforce-identity-federation

IAP (Identity-Aware Proxy) とは

IAP (Identity-Aware Proxy) は、Cloud Run などのアプリケーションや Virtual Machine へのアクセスを制御(認証・認可)を行うリバース プロキシ サービスです。
IAP によって保護されているアプリケーションは、適切な IAM ロールを持つプリンシパルのみアクセスできます。
https://cloud.google.com/iap/docs/concepts-overview

Workforce Identity 連携して Microsoft Entra で IAP 認証してみる

本記事では、次のドキュメントの流れに沿って操作を行っていきます。
https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad?hl=ja

https://cloud.google.com/iap/docs/use-workforce-identity-federation?hl=ja

Workforce Identity プールの作成

まずは Workforce Identity プールを作成します。
組織ノードに移動し、IAM と管理 > Workforce Identity の連携に移動します。

プールを作成をクリックして、Workforce Identity プールを作成します。
今回は test-entra-pool という名前で作成します。

作成完了までしばらく待つ必要があります。

Workforce Identity プールの作成は以上です。

Microsoft Entra テナントでエンタープライズ アプリケーションを作成

Workforce Identity プールに追加できるプロバイダは、OIDC プロトコルと SAML プロトコルをサポートしています。

SAML の気分だったので、今回は SAML プロトコルを利用して設定していきます。

Azure Portal にアクセスし、Microsoft Entra テナントでエンタープライズ アプリケーションを作成します。

独自のアプリケーションの作成をクリックします。

アプリケーションに任意の名前を付けます。
今回は test-workforce-identity という名前でアプリケーションを作成します。

続いてシングル サインオンの設定に移動し、シングル サインオン方式の選択で SAML を選択します。

基本的な SAML 構成の編集をクリックし、識別子(エンティティ ID)、応答 URL(Assertion Consumer Service URL)、リレー状態を構成します。

各項目を以下のように設定します。

  • 識別子 (エンティティ ID)
    https://iam.googleapis.com/locations/global/workforcePools/<プール ID>/providers/<プロバイダID>
  • 応答 URL (Assertion Consumer Service URL)
    https://auth.cloud.google/signin-callback/locations/global/workforcePools/<プールID>/providers/<プロバイダ ID>
  • リレー状態
    https://console.cloud.google/

プール ID は先程作成した Workforce Identity プール ID、プロバイダ ID は後ほど Google Cloud 側で設定する任意の Workforce Identity プロバイダ ID を入力してください。

続いて、 Workforce Identity 側に送る情報を設定するため、属性とクレームの編集をクリックします。

本記事では認証できるのが目的なので、Microfot Entra アカウントの UPN を送るように設定します。
必要な要求の値には user.userprincipalname を設定し、追加の要求はすべて削除しています。

次にユーザーとグループをクリックし、このエンタープライズ アプリケーションを利用するユーザーまたはグループの割り当てを行います。

今回は、oda というユーザーを割り当てました。

最後に Workforce Identity の設定でフェデレーション メタデータ XML が必要なので、
シングル サインオンのページからダウンロードしておきます。

以上で、Microsoft Entra テナント側で準備は終わりです。

Workforce Identity プール にプロバイダを追加する

次に、Google Cloud コンソールに戻り、Workforce Identity プールにプロバイダを追加します。

今回は、以下のように設定しました。

  • プロバイダの選択
    SAML
  • 名前とプロバイダ ID
    先ほど Microsoft Entra のエンタープライズ アプリケーションに設定したプロバイダ ID
  • IDP メタデータ ファイル (XML)
    先ほど Microsoft Entra のエンタープライズ アプリケーションでダウンロードしたフェデレーション メタデータ XML

続行をクリックし、属性のマッピングを設定します。
今回はは、google.subject に対応する値として assertion.subject を入力しました。

設定完了後、プロバイダのステータスが有効になっていることを確認します。

IAP の設定

先に Cloud Run のアプリケーションにグローバル外部アプリケーション ロードバランサを設定しておきます。

Cloud Run のデプロイと、グローバル外部アプリケーション ロードバランサの設定

動作確認のため HTTP リクエスト ヘッダーを表示する、簡単なアプリケーションを Buildpack を利用してデプロイしています。

gcloud run deploy test --source=. --platform=managed --allow-unauthenticated --ingress=internal-and-cloud-load-balancing --region=asia-northeast1

Cloud Run アプリケーションのコード

main.go
package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	h := r.Header
	fmt.Fprintln(w, h)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

今回は、Cloud Run Integration を利用してグローバル外部アプリケーション ロードバランサ構成します。
https://cloud.google.com/run/docs/integrate/custom-domain-load-balancer?hl=ja

カスタム ドメイン - Google Cloud Load Balancing を選択します。

所有しているドメインを指定して作成します。

作成完了後、表示されたロードバランサの IP アドレスを DNS レコードを設定します。

Identity-Aware Proxy API を有効化します。

IAP の OAuth Client を作成します。
Cloud Shell 等で以下のコマンドを実行します。

gcloud iam oauth-clients create <OAUTH クライアント ID> \
    --project=<プロジェクトID> \
    --location=global \
    --client-type="CONFIDENTIAL_CLIENT" \
    --display-name="Test OAuth" \
    --description="Test OAuth" \
    --allowed-scopes="https://www.googleapis.com/auth/cloud-platform" \
    --allowed-redirect-uris="https://example.com" \
    --allowed-grant-types="authorization_code_grant"

次に作成した OAuth Client を確認します。
以下のコマンドを実行します。

gcloud iam oauth-clients describe <OAUTH クライアント ID> \
    --project <プロジェクト ID> \
    --location global

コマンド実行結果

allowedGrantTypes:
- AUTHORIZATION_CODE_GRANT
allowedRedirectUris:
- https://example.com
allowedScopes:
- https://www.googleapis.com/auth/cloud-platform
clientId: xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
clientType: CONFIDENTIAL_CLIENT
description: Test OAuth
displayName: Test OAuth
name: projects/<プロジェクト ID>/locations/global/oauthClients/<OAUTH クライアント ID>
state: ACTIVE

上記の結果から clientId の値をメモしておきます。

以下のコマンドを実行し、承認済みのリダイレクト URI を https://iap.googleapis.com/v1/oauth/clientIds/<clientId の値>:handleRedirect に更新します。

gcloud iam oauth-clients update <OAUTH クライアント ID> \
    --project=<プロジェクト ID> \
    --location=global \
    --allowed-redirect-uris="https://iap.googleapis.com/v1/oauth/clientIds/<先ほどの clientId の値>:handleRedirect"

OAuth Client の認証情報を作成します。
以下のコマンドを実行します。

gcloud iam oauth-clients credentials create <クライアント認証情報 ID> \
    --oauth-client=<OAUTH クライアント ID> \
    --display-name='Test OAuth Credential' \
    --location='global'

作成した認証情報のクライアント シークレットの値を確認します。
以下のコマンドを実行します。

gcloud iam oauth-clients credentials describe <認証情報 ID> \
    --oauth-client=<OAUTH クライアント ID> \
    --location='global'

コマンド実行結果

clientSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
displayName: Test OAuth Credential
name: projects/<プロジェクト ID>/locations/global/oauthClients/<OAUTH クライアント ID>/credentials/<クライアント認証情報 ID>

上記の結果から clientSecret の値をメモしておきます。

次に Workforce Identity 連携を使用する IAP 構成するための設定ファイルを作成します。
以下の内容で iap_settings.yaml を作成します。

iap_settings.yaml
access_settings:
  identity_sources: ["WORKFORCE_IDENTITY_FEDERATION"]
  workforce_identity_settings:
    workforce_pools: ["locations/global/workforcePools/<プールID>"]
    oauth2:
      client_id: "<gcloud iam oauth-clients describe コマンド結果の clientId>"
      client_secret: "<gcloud iam oauth-clients credentials describe コマンド結果の clientId>"

IAP を利用する Cloud Run に設定されたロードバランサの設定などから、バックエンドサービス ID を確認し、以下のコマンドで IAP を構成します。

gcloud iap settings set iap_settings.yaml --project=<プロジェクト ID> \
    --resource-type=compute \
    --service=<バックエンドサービス ID>

以下のコマンドで IAP を有効化します。

gcloud compute backend-services update <バックエンドサービス ID>> \
    --global --iap=enabled

最後に、ログインさせたいユーザーに IAP で保護されたウェブアプリ ユーザー(roles/iap.httpsResourceAccessor)ロールを付与します。
今回の構成だと、Microsoft Entra テナントから UPN を受け取っているため、以下のようなプリンシパル名を入力します。
principal://iam.googleapis.com/locations/global/workforcePools/<プール ID>/subject/<Microsoft Entra アカウントの UPN>

以上で IAP の設定についても完了です。

Entra ID で Cloud Run にアクセスしてみる

Cloud Run の ロードバランサに設定したドメインにアクセスして、IAP の動作を確認します。

Google アカウントではなく、Microsoft アカウントのログイン画面が表示されました。

アカウント名とパスワードを入力後、一瞬リダイレクトの画面が表示されます。

Cloud Run のアプリケーションにアクセスできました。

今回設定した通り、HTTP リクエスト ヘッダーの情報が表示されました。

通常の IAP 構成であれば X-Goog-Authenticated-User-Email ヘッダーに、アクセスしているユーザーのメールアドレスが含まれているようですが Workforce Identity 連携の IAP だとありませんでした。
そのためユーザーのメールアドレスをヘッダーから特定するのは難しそうです。

また X-Goog-Authenticated-User-Id ヘッダーは通常の accounts.google.com:userIDvalue という形式の値ではなく sts.google.com:userIDvalue という形式で値が入っていました。
https://cloud.google.com/iap/docs/identity-howto?hl=ja#getting_the_users_identity_with_signed_headers

まとめ

本記事では、Workforce Identity 連携と IAP を利用し、Microsoft Entra アカウントで Cloud Run のアプリケーションに IAP 認証をしてみました。

アプリケーションのインフラは Google Cloud を利用しているが Microsoft Entra アカウントで認証したいというような構成は私の周りだとよく見るので、構成に選択肢が増えたのはとてもありがたいです。

今回の例では Cloud Run を使用しましたが、Compute Engine など他の IAP に対応したサービスでも同様の設定ができると思いますので、ぜひ導入を検討してみてください。

Discussion