最近、Google Cloudが古くから提供しているPaaSのGoogle App Engine(GAE)で社内用のアプリケーションを作りました。基本的なセキュリティ対策として、自社のGoogle Workspaceアカウントと関連会社のGoogle WorkspaceアカウントだけがアクセスできるようにしたくてIAP(Identity-Aware Proxy)を設定しようとしたのですが、なぜかうまくいかず、いろいろ試行錯誤したうえでようやく解決しました。忘れないように、今回は備忘録がてら解説を書こうと思います。
IAPとは何か
はじめにIAPというものを整理しておきます。IAPとはひとことでいえば、Google Cloud上に構築したWebページやWebアプリケーションへアクセスする際、ユーザーのIDに基づいてアクセスの可否を制御できる仕組みです。今回はGAEですが、Cloud Run、Compute Engine、Google Kubernetes Engine (GKE)などで構築したページにも適用可能です。
IAPというのはGoogle Cloudでの呼び方ですが、他の主要パブリッククラウドでも同様の機能が提供されています。
IdentityというのはユーザーのID。Awareは「認識して」という意味。Proxy(プロキシ)は、ユーザーがWebサイトへアクセスする際に、ユーザーに代わってインターネット通信を中継するものです。
イメージとしては、Google Cloud上のWebページとユーザーの間に代理人がいて、その代理人がアクセスしたユーザーのIDを確認し、それが許可されているものであった場合は代理人がユーザーの代わりにWebページにアクセスして、その結果をユーザーに返してあげる、という感じでしょうか。
詳細は、Google Cloudの公式ドキュメントをご覧ください。
IAPの設定方法
以下、IAPの設定手順を紹介します。
まず、Google Cloudの左側のメニューの「セキュリティ」>「Identity-Aware Proxy」から設定します。ただし、この機能を利用するためにはAPIを有効化する必要があります。「APIとサービス」の中からでも設定できますが、最初に「Identity-Aware Proxy」へアクセスすると、APIを有効化するボタンがあるのでそこからでも大丈夫です(下図)。

IAP画面での設定はシンプルです。以下の私の環境の画面では、すでにGAEでアプリを構築しているので、「すべてのウェブサービス」というところにGAEアプリがあります。
対象のアプリを選択して、IAPのトグルボタンをオンにした上で、下図に示す右側のサイドパネルの「ロール/プリンシパル」で権限を設定します。

ロールというのはそのユーザーに何を許可するかという項目です。私もそれぞれのロールの詳細は把握していませんが、今回行いたいのは、ユーザーがブラウザから対象のWebページへのアクセスできるようにする設定です。これを実現するためのロールは、下図にある通り「IAP-secured Web App User」というロールであり、そこにアクセスを許可するユーザーのメールアドレスもしくはドメイン名を設定していきます。
ちなみに、今回紹介するこのIAPはGoogleの認証情報をアクセス制御の判断材料として使うので、ユーザーやドメインはGoogle アカウントと紐づいていることを前提とします。このIAPでアクセス制御できるのは、Googleアカウントだけです。それ以外のアカウントの場合、GoogleとID連携を行うことで可能になるそうです。

これだけではまだIAPは機能しません。次に「OAuthクライアント」の設定を行います。
この「OAuth」とは何なのか?について説明すると長くなるので省きますが、認可のためのプロトコルの1つです。このプロトコルでは、「OAuthクライアント」「シークレット」「アクセストークン」のキーワードがよく出てくるので、先にその言葉を説明します。
OAuthクライアントとは、例えるならアクセスしようとしているユーザーが「入場するための招待状」みたいなものです。IAPが「誰か」を識別してアクセス制御するためには、当然ながらアクセスしようとしている人が匿名であっては識別できないからです。
ただ、それだけでは十分ではありません。例えば、Aさんの招待状が盗まれ勝手に使用されたら、Aさんの招待状でBさんもCさんも入れてしまうからです。なので、この招待状をAさんが使用するときに、それが「本当にAさんのものである」ことを証明するものが必要です。それが「シークレット」です。
こうして、招待状を持って通行しようとした際に、守衛の人は認可サーバーに確認を取り、確認が取れたら入場券をユーザーに渡します。この入場券がアクセストークンです。
OAuthの設定
このOAuthの設定を行うには、IAPの設定画面で、対象となるアプリの右の方にある3点メニューから「設定」をクリックします。

すると「OAuthの構成」というところに、
という2つの選択肢があります。

このうち、今回は外部のユーザーのアクセス制御を行いたいので、「カスタム OAuth」の方を使用します。上記の画面に書かれているように、これを構成するには、まず「OAuth 同意画面」を構成する必要があります。そのため、「カスタム OAuth」のラジオボタンを選択する前に、その下にある「同意画面を構成」をクリックしてその設定を行います。
ちなみに、「OAuth 同意画面」というのは、その名の通り、「OAuthという仕組みに基づいて、あなたのGoogleの認証情報を使ってアプリを通信できるようにしますよ。許可しますか?」というユーザーの合意を取るための画面です(その画面は実際このあとの説明で示します)。
この「同意画面の構成」はGoogle Cloudの全体メニューの「Google Auth Platform」>「OAuth同意画面」から行います。ここは最初にアクセスすると、まだ設定がなされておらず、以下のように「Google Auth Platform はまだ構成されていません」と表示されます。

上記画面で「開始」を押したあと、プロジェクトの構成で、
- アプリ情報
- 対象
- 連絡先情報
の3つの情報を設定します。

対象は、「内部」と「外部」ありますが、今回は組織以外の人にも共有するため「外部」を選択します。(※以下の画面はすでに「外部」を設定済みの画面です)

これで最後に「作成」を押すと、OAuth 同意画面の構成はいったん完了です。ただ、これでまだ完了ではありません。先ほども触れましたが、アクセス制御するには、認証情報が必要です。具体的には、身分証と本人を証明する「OAuthクライアント」と「シークレット」が必要です。
これは同じく「Google Auth Platform」のメニューから「クライアント」を選択して、手動で作成できるのですが、それより簡単な方法があります。先ほどのOAuthの構成を設定する画面(下図)に、「認証情報を自動生成」というボタンがあるのでそれをクリックすると自動で発行されます。

これを実行すると、上記の画面の「クライアントID」と「クライアント シークレット」という部分に自動的に入力されます。
実際に「Google Auth Platform」のメニューから「OAuthクライアント」を見てみると、以下のように、OAuthクライアントが自動的に生成されていることがわかります。

このOAuthクライアントに関して、右側の鉛筆アイコンをクリックして設定を見てみると、その中に「承認済みのリダイレクト URI」という設定項目があるのですが、それも自動的に入力されています。このURIは以下のような形になっており、赤い部分にOAuthクライアントIDが入るかたちとなっています。
https://iap.googleapis.com/v1/oauth/clientIds/xxx.apps.googleusercontent.com:handleRedirect
「承認済みのリダイレクト URI」とは認証コードを安全に受け渡すために存在します。ユーザーがIAPを通じて対象のサイトにアクセスする際、まずGoogleの認証情報でログインする許可をGoogleの認証サーバーでもらったあとに、今度はアクセスしようとする対象のサイトに認証コードを渡さなければなりません。
ここで、もし認証サーバーで認証した後に、任意のページにリダイレクトできてしまった場合、例えばサイバー攻撃者が何らかの形で介在できる余地を残してしまい、認証サーバーから返ってきた認証コードが窃取されてしまいます。そのため、「承認済みのリダイレクト URI」という項目で、リダイレクト先はあらかじめ特定のものに設定しておく必要があるのです。
実際にサイトへアクセスしてみる
さて、これにてIAPの設定とOAuthの構成が完了したので、実際に対象のアクセス制御対象のWebページのURLにアクセスしてみましょう。
以下のように、Googleのサービスにログインする際に現れるアカウント選択の画面が出てきます。

事前にアクセス許可リストに入れたアドレス(Google Workspaceに紐づいたドメイン)を選択します。次はこのような画面になります。

実際のアクセス先のサイトはテストページで何の変哲もないので割愛しますが、上記画面で「次へ」を許可すると無事にサイトにアクセスできました。
今回は事前に許可されたアドレスだったのでログインできましたが、もしアクセス権限が与えられていないGoogleアカウントでアクセスすると、以下のようにアクセスが拒否されます。

ちなみに、今回は組織外部のユーザーを含めたアクセス制御を実現するユースケースとして、OAuthの構成で、「外部」を選択しましたが、これが自社の従業員だけがアクセスできるようにしてそれ以外のドメインやGoogleアカウントからのアクセスを拒否したい場合、つまり「内部」の場合、設定はもっとシンプルに行うことができます。
その方法としては、先ほどのこちらの画面にて上の「Google 管理の OAuth(シンプルに行うためにはこちらを推奨)」を設定するだけでOKです。

これはGoogleがもともと内部的に用意されているOAuthクライアントを使っているらしく、この場合ユーザーが明示的にOAuthクライアントとシークレット、承認済みURIなどを設定する必要はありません。
注意点
1つだけ注意点です。Webブラウザを通じたサイトへのアクセスは、すでに説明した通り、「IAP-secured Web App User」というロールに、アクセスさせたいプリンシパルを設定していますが、ここに管理者は自動的に追加されません。
つまり、このアプリのプロジェクトオーナーのアドレスまたはドメインを手動で追加しない限り、アプリのオーナーですらアクセスがブロックされます。
「オーナーなんだから自動的にアクセス権を付与しても良いのでは」と思ったのですが、私と同じ疑問を持つ人が多いのか、公式ドキュメントのIAPのクイックスタートガイドのページに、ちゃんとその理由が書かれていました。

つまり、「人事システム」というシステムの開発と運用を管理するのは情シスだが、実際に人事システムにアプリにアクセスするのは情シスではないユーザーなのだから、情シスには自動的にアプリへのアクセス権は付与しないよ、ということです。まぁ確かにそう聞くとその通りですよね。
以上です。ちなみに、これは私が社内アプリのアクセス制御のためにいろいろGeminiに聞きながらたどり着いたもので、IAPに関して詳しいものではなく、むしろ普段システム開発に関わっていない人間であり、素人です。
素人がこの設定を実現するのに非常に苦労してしまったので、備忘録的に残しておきました。上記に書いてある手順が正しいかどうか、他にも設定するべきところがあるか不明ですので、あくまで参考程度にご覧ください。