Google Cloud の IDaaS「Identity Platform」で作る、さまざまな認証パターン
Identity Platform を使うと、さまざまな認証パターンが構築できる!
この記事は2023年10月6日に行われたナレッジワークさん主催のイベント「Encraft #7 AppDev with Google Cloud」で発表したセッションの解説記事です。現地でご参加いただいた皆さん、オンラインでご視聴いただいた皆さん、ありがとうございました!
私のセッションでは Identity Platform を使ったさまざまな認証パターンについてご紹介しました。セッション後、いくつかのご質問や「こんなパターンもあるよ!」というコメントもいただきました(ありがとうございます!)。この記事では、セッション内でご紹介した内容に加え、別解、または発展系とも言えるいくつかのパターンについてもご紹介します。
Identity Platform とは
まずはこの記事でメインで扱う Identity Platform について、クイックにご紹介したいと思います。
Identity Platform は Google Cloud で提供している認証サービスです。モバイルアプリ、Web アプリに認証機能をかんたんに導入できます。Firebase Authentication の上位版という位置付けで、Firebase Authentication の機能に加えて下記の機能も提供しています。
- 多要素認証 (MFA)
- ブロッキング関数を使った認証フローのカスタマイズ
- OpenID Connect (OIDC) プロバイダ、SAML プロバイダのサポート
- Cloud Logging を使ったユーザー アクティビティ ログと監査ログによるモニタリング
- App Check による不正行為の防止
- マルチテナンシー
- エンタープライズサポートと SLA (99.95%)
- 匿名ユーザーの自動クリーンアップ
- HIPPA の適用
- Identity-Aware Proxy (IAP) との統合
Firebase Authencation を知っている(または使っている)方は多いと思いますが、より高度な機能を使いたい場合は Identity Platform にアップグレードが可能です。ユーザーの移行も必要ないほか、クライアント側で使う必要がある SDK も Firebase Authencation で使っている SDK をそのまま使うことができるので、かんたんにアップグレードできます。
SPA + Identity Platform (アプリからの認証)
まずは SPA (Single Page Application) に Identity Platform を導入するシンプルな構成です。
SPA (例 : React) は Cloud Storage にアップロードした静的ファイルを Application Load Balancer + Cloud CDN でキャッシュを効かせる構成でホスティングします。Identity Platform の JavaScript SDK を使用してユーザー登録、およびログインを実行します。
API サーバーへのリクエストは、Identity Platform から取得した ID トークンを Authorization ヘッダーに付けて送ります。API サーバー側では受けたリクエストから ID トークンを取得し、署名のチェックやユーザーの特定、認可などの処理を実装します。
実装方法は下記のドキュメントが参考になります。
- Identity Platform を使用してユーザーがメールアドレスでログインできるようにする | Identity Platform
- ID トークンを検証する | Firebase Authentication
- ユーザーの認証 | Cloud Run
SSR + Identity Platform (アプリからの認証 + サービス間認証)
次は Web アプリを SSR (Server Side Rendering) にした場合の構成です。SSR (例 : Next.js) は Cloud Run にコンテナ化してデプロイします。Application Load Balancer と Cloud CDN の構成は SPA の構成と同様です。
SPA 側の ID トークンの取得も同様ですが、SSR が入る場合は SSR 側で API リクエストを行いたい場合があります。その場合は Cloud Run から Cloud Run への認証が必要となるため、SSR 側の Cloud Run のサービスアカウントに API サーバー側の Cloud Run 起動元の権限を付与する必要があります。SSR 側の Cloud Run の中では ID トークンを取得し、API リクエストに Authorization ヘッダーを付与します。API サーバー側では Authorization ヘッダーから ID トークンを取得し、署名のチェックやユーザーの特定、認可などの処理を実装します。
また、SSR サーバーがレンダリングしたあとのブラウザ側から API リクエストも行いたい場合は SPA の構成と同様、Identity Platform から ID トークンを取得、API リクエストに Authorization ヘッダーを付与する実装を行います。API サーバー側ではブラウザ側から送信された ID トークン、SSR 用の Cloud Run から送信された ID トークン、2種類に対して署名のチェックやユーザーの特定、認可などの処理を行う必要があります。
実装方法は下記のドキュメントが参考になります。
Identity-Aware Proxy (IAP) による保護
Identity-Aware Proxy (IAP) は Cloud Run などのアプリケーションへのアクセスを保護するためのサービスです。ユーザー ID を確認し、コンテキストに応じてアクセスの許可・拒否を判断させることができます。
IAP はアクセスを許可するユーザーを Google アカウント、または Google グループなどで IAM を使用して指定します(外部 ID を許可することもできますが後述します)。IAP は Load Balancer に設定することで、Load Balancer へのアクセス時に IAP によるユーザーの認証画面を表示し、アクセスが許可されたユーザーであることが確認できたらバックエンドの Cloud Run にリダイレクトするような振る舞いをします。
IAP を使うと Cloud Run 側でユーザーのアクセスを許可するかどうかを判断する必要がないため、アクセス制御をかんたんに導入でき便利です。一方で細やかな認可 (例 : ユーザーの属性によって API リクエストを許可するか判断する) を行いたい場合は Cloud Run 側で実装する必要があります。また、Cloud CDN との併用はできません。
実装方法は下記のドキュメントが参考になります。また、試す場合でも Load Balancer は SSL を有効化しておく必要があります。
Identity Platform を使って IAP で外部 ID を許可する
IAP では Identity Platform を使用して、外部 ID でログインされたユーザーのアクセス制御を行うことができます。外部 ID を有効化すると、Google アカウントに限らず、Identity Platform がサポートする種類のプロバイダを使用することができます。
- メールアドレスとパスワード
- OAuth (Google、Facebook、X など)
- SAML
- Open ID Connect (OIDC)
- 電話番号 (SMS)
- 匿名
なお IAP では Identity Platform を使用した場合、ログインページを用意する必要があります。ログインページは下記の2つのいずれかが設定可能です。
- Cloud Run を使用して作成する
- 独自の UI を用意する
Cloud Run を使用して作成する方法を使うと、UI の表示やログイン処理などがあらかじめ実装された Cloud Run をクイックにデプロイできます。UI のカスタマイズも可能なので、固有の要件などがない限りは必要な処理を自身で実装しなくて済むためおすすめです。独自の要件がある場合、フルカスタマイズしたい場合はカスタムしたログインページを用意し、デプロイします。
実装方法は下記のドキュメントが参考になります。
- 外部 ID の有効化 | Identity-Aware Proxy
- Cloud Run を使用したログインページのホスティング | Identity-Aware Proxy
- FirebaseUI を使用したログインページの作成 | Identity-Aware Proxy
- カスタム ログインページの作成 | Identity-Aware Proxy
API サーバーに IAP を適用する (Cloud Run to Cloud Run)
API サーバーに IAP を適用する場合、Web アプリから API サーバーにリクエストする際の認証について考えなければいけません。ここでは、まず SSR 用の Cloud Run から API サーバー用の Cloud Run へのリクエストについて考えます。
まず初めに思いつくところが「IAP を挟んでいるのであれば、IAP で認証した情報を使えば良いのでは?」という点です。IAP は認証後、 X-Serverless-Authorization ヘッダーに ID Token を付与して Cloud Run にリダイレクトします。しかし X-Serverless-Authorization ヘッダーに設定された ID Token からは署名情報が削除された状態で渡されます。したがって、この ID Token を使って API リクエストを行った場合、API サーバー側では署名の検証ができません。別な方法で認証を通す必要があります。
API サーバーに API リクエストを送るには、2通りの経路が考えられます。
- Load Balancer を経由してリクエストする
- Cloud Run に直接リクエストする
前者の Load Balancer 経由で API リクエストをする場合は Load Balancer に IAP が適用されているので、後述する IAP の認証を通す構成になります。後者の方法は Load Balancer を経由せず、Cloud Run から Cloud Run に対してサービス間認証を実装することで対応が可能です。
API サーバーに IAP を適用する (Cloud Run to Load Balancer)
前述の通り、IAP を介して API リクエストを送る場合は IAP の認証をどのように通すか考慮する必要があります。
IAP ではプログラムで ID Token をすでに取得している場合に、その ID Token を使って認証を通すための機能を提供しています。プログラムによる認証の機能を使うことで、SSR 用の Cloud Run のサービスアカウントの ID Token を使って IAP の認証を通すことができます。
設定方法もシンプルで、IAP で保護するユーザーリストに SSR 用の Cloud Run のサービスアカウントを追加し、リクエスト時に Authorization ヘッダーにサービスアカウントの ID Token を付与するだけです。なお、Authorization ヘッダーがすでに別な用途で使用されていて使えない場合は Proxy-Authorization ヘッダーを代わりに使うこともできます。
API サーバーに IAP を適用する (Identity Platform + IAP)
Web アプリ側で Identity Platform へのログインを実装していて、Web アプリ側で取得した ID Token をそのまま IAP を介して API サーバーへのリクエストに使う方法です。
この構成を実現する場合も Cloud Run からリクエストする場合と同様、Identity Platform から取得した ID Token を Authorization ヘッダーに付与するだけで認証を通すことができます。
この構成はクライアントがモバイルアプリの場合に有効です。モバイルアプリ側では通常、まず Identity Platform に対してログイン処理を行い、そのあとで API サーバーへのリクエストを行うフローになります。一方 Web アプリの場合はこの構成だけだと難しく、初回アクセス時にまず IAP が認証を求めるため、Web アプリ側で ID Token が取得できるのは IAP で認証したあとになってしまいます。
API サーバーに IAP を適用する (OAuth クライアント共有)
前述の「API サーバーに IAP を適用する (Identity Platform + IAP)」で難しかった「Web アプリの認証」の課題を解決できるのがこの構成です。
IAP は、Google が管理する OAuth クライアントを使用してユーザーを認証する仕組みです。この OAuth クライアントは Load Balancer のバックエンドごとに設定しますが、この OAuth クライアントを SSR 用の Cloud Run のバックエンドと API サーバー用の Cloud Run のバックエンドで共有することができます。これにより SSR を開く際に IAP 経由で認証したあと、API サーバーへのリクエストも認証された状態にできます。
こちらを設定したい場合、Google Cloud コンソールではサポートされていないため API を使用して設定する必要があります。
- IAP の OAuth クライアントをプログラムで作成 | Identity-Aware Proxy
- OAuth 構成をカスタマイズして IAP を有効にする | Identity-Aware Proxy
gcloud
コマンドで設定する場合は次のようになります。
$ gcloud compute backend-services update <SERVICE NAME> \
--global \
--iap=enabled,oauth2-client-id=<CLIENT ID>,oauth2-client-secret=<CLIENT SECRET>
また、例えば組織レベルやフォルダレベルで共有したい場合、任意のレベルでまとめて許可リストに加えることもできます。こちらも API を使用した設定のみサポートしています。
OAuth クライアントを共有する方法は実装上、あるいはユーザー体験の観点から便利ですが、次のようなリスクもあります。これらのリスクがあることを理解し、考えられる対策の導入も検討した上、適した要件のみで使用するようにしてください。
- OAuth クライアントが単一障害点となるので、設定を変更したり削除した場合はすべてのクライアントに影響する
- 設定時にクライアントシークレットを共有する必要があるため、漏洩のリスクが高まる
- クライアントシークレットが漏洩した場合、すべてのクライアントでユーザーのなりすましが可能になる
- クライアントシークレットが漏洩した場合、アプリのユーザー ID を収集する可能性がある
まとめ
シンプルな構成から、少し複雑な構成までいくつかの構成をご紹介しました。
特に後半はちょっと複雑、かつ要件が近しい構成が続いていますが、要件によってどの構成を採用すべきか変わってきますので、ぜひ本ブログを参考にしつつ試しながら選んでいただければと思います。
本ブログではすべてのパターンを網羅しているわけではありませんが、いずれかの情報がお役に立てば幸いです。
Discussion