App Engine などの Google Cloud マネージド プラットフォームで実行するアプリは、Identity-Aware Proxy(IAP)を使用することにより、ユーザー認証やセッション管理の手間を省いてアプリへのアクセスを制御できます。IAP は、アプリへのアクセスを制御できるだけでなく、新しい HTTP ヘッダーの形式でメールアドレスや永続的な識別子などの認証済みユーザーに関する情報をアプリに提供することもできます。
目標
IAP を使用することにより、App Engine アプリのユーザーに自分自身を認証するように要求する。
アプリでユーザーの ID にアクセスして、現在のユーザーの認証済みメールアドレスを表示する。
料金
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
- Install the Google Cloud CLI.
-
To initialize the gcloud CLI, run the following command:
gcloud init
背景
このチュートリアルでは、IAP を使用してユーザーを認証します。これは、いくつかのアプローチのうちの 1 つにすぎません。ユーザーのさまざまな認証方法の詳細については、認証のコンセプトセクションをご覧ください。
Hello user-email-address
アプリ
このチュートリアル用のアプリは、最小の Hello world App Engine アプリで、「Hello world」の代わりに「Hello user-email-address
」を表示する特別な機能を備えています。ここで、user-email-address
は認証済みユーザーのメールアドレスです。
この機能は、IAP がアプリに渡す各ウェブ リクエストに追加する認証情報を調べることで可能になります。アプリに届くリクエストには 3 つの新しいリクエスト ヘッダーが追加されます。最初の 2 つのヘッダーは、ユーザーの識別に使用できる書式なしテキスト文字列です。3 つ目のヘッダーは、同じ情報を含む暗号署名付きオブジェクトです。
X-Goog-Authenticated-User-Email
: ユーザーのメールアドレスでユーザーが識別されます。アプリで回避できる場合は、個人情報を保存しないようにしてください。このアプリはデータを保存しません。ユーザーにエコーバックするだけです。X-Goog-Authenticated-User-Id
: Google が割り当てたこのユーザー ID は、ユーザーに関する情報は表示しませんが、ログインしているユーザーが過去に表示されたユーザーと同じであることをアプリが認識できるようにします。X-Goog-Iap-Jwt-Assertion
: インターネット ウェブ リクエスト以外に、IAP を迂回してきた他のクラウドアプリからのウェブ リクエストを受け入れるように Google Cloud アプリを構成できます。アプリがこのように構成されている場合は、このようなリクエストのヘッダーが偽造されている可能性があります。上記のいずれかの書式なしテキスト ヘッダーを使用する代わりに、この暗号署名付きヘッダーを使用して、情報が Google から提供されたものであることを確認できます。ユーザーのメールアドレスと永続的なユーザー ID の両方をこの署名付きヘッダーの一部として使用できます。
アプリが、インターネット ウェブ リクエストのみを受け入れ、アプリに対する IAP サービスを無効にできないように構成されている場合は、一意のユーザー ID を取得するコードは 1 行で済みます。
userId = req.header('X-Goog-Authenticated-User-ID') :? null;
ただし、回復性の高いアプリは予期せぬ構成や環境問題などの障害を想定しておく必要があるため、代わりに、暗号署名付きヘッダーを使用して確認する関数を作成することをおすすめします。ヘッダーの署名は偽造できないため、検証時に、識別を返すのに使用できます。
ソースコードを作成する
テキスト エディタを使用して、
app.js
という名前のファイルを作成し、次のコードを貼り付けます。この
app.js
ファイルの詳細については、このチュートリアルの後半のコードについてセクションで説明します。package.json
という名前の別のファイルを作成し、次のコードを貼り付けます。package.json
ファイルには、アプリに必要な Node.js 依存関係がすべて一覧表示されます。jsonwebtoken
は、JWT のチェックおよびデコード機能を提供します。app.yaml
という名前のファイルを作成し、次のテキストを入力します。app.yaml
ファイルは、コードが必要とする言語環境を App Engine に指示します。
コードの説明
このセクションでは、app.js
ファイル内のコードが機能する仕組みを説明します。アプリを実行する場合は、アプリをデプロイするセクションまでスキップできます。
次のコードが app.js
ファイルに格納されています。アプリが HTTP GET
を受信した場合、/
のスイッチケースが呼び出されます。
この関数は、IAP が受信リクエストから追加した JWT アサーション ヘッダー値を取得し、その暗号署名値を検証する関数を呼び出します。返される最初の値(メールアドレス)は、作成されて返される最小限のウェブページで使用されます。
validateAssertion
関数は、google-auth-library
からの verifySignedJwtWithCertsAsync()
関数を使用して、アサーションが適切に署名されていることを確認し、アサーションからペイロード情報を抽出します。この情報は、認証済みユーザーのメールアドレスと永続的な一意の ID です。アサーションをデコードできない場合、この関数はエラーをログに記録するためのメッセージをスローして出力します。
JWT アサーションを検証するには、アサーションに署名した機関(この場合は Google)の公開鍵証明書と、アサーションの対象オーディエンスを把握している必要があります。App Engine アプリの場合、オーディエンスは Google Cloud のプロジェクト識別情報を含む文字列です。この関数は、それらの証明書とその前の関数からのオーディエンス文字列を取得します。
Google Cloud プロジェクトの数値 ID と名前を検索し、ソースコード内に配置することもできますが、audience
関数がすべての App Engine アプリで使用可能になっている標準のメタデータ サービスをクエリすることで代行します。メタデータ サービスはアプリコードの外部にあるため、結果はグローバル変数に保存され、後続の呼び出しでメタデータを検索する必要はありません。
App Engine のメタデータ サービス(および他の Google Cloud コンピューティング サービスの類似のメタデータ サービス)は、ウェブサイトのように見え、標準のウェブクエリによって照会されます。ただし、メタデータ サービスは実際には外部サイトではなく、実行中のアプリに関する情報を返す内部機能であるため、https
リクエストの代わりに http
リクエストを使用しても安全です。これは、JWT アサーションの対象オーディエンスを定義するために必要な現在の Google Cloud 識別子を取得するために使用されます。
デジタル署名を検証するには、署名者の公開鍵証明書が必要です。Google では、現在使用されているすべての公開鍵証明書を返すウェブサイトを提供しています。これらの結果は、同じアプリ インスタンス内で再び必要になる場合に備えてキャッシュに保存されます。
アプリのデプロイ
これで、アプリをデプロイして、次いで Cloud IAP でユーザーが認証しないとユーザーがアプリにアクセスできないようにできます。
ターミナル ウィンドウで、
app.yaml
ファイルが格納されたディレクトリに移動して、アプリを App Engine にデプロイします。gcloud app deploy
プロンプトが表示されたら、最寄のリージョンを選択します。
デプロイ操作を続行するかどうかを尋ねられたら、
Y
と入力します。数分以内に、アプリがインターネット上に公開されます。
次のようにしてアプリを表示します。
gcloud app browse
出力で、
web-site-url
(アプリのウェブアドレス)をコピーします。ブラウザ ウィンドウで、
web-site-url
を貼り付けてアプリを開きます。IAP をまだ使用していないのでメールが表示されないため、ユーザー情報がアプリに送信されません。
IAP を有効にする
これで App Engine インスタンスが存在するようになり、IAP を使用して保護できます。
Google Cloud Console で、[Identity-Aware Proxy] ページに移動します。
今回はこのプロジェクト用の認証オプションを初めて有効にしたため、IAP を使用するには OAuth 同意画面を構成する必要があることを示すメッセージが表示されます。
[同意画面を構成] をクリックします。
[認証情報] ページの [OAuth 同意画面] タブで、次のフィールドに値を入力します。
アカウントが Google Workspace の組織にある場合は、[外部] を選択して [作成] をクリックします。開始すると、アプリは明示的に許可されたユーザーのみが利用できます。
[アプリケーション名] フィールドに、
IAP Example
と入力します。[サポートメール] フィールドに、メールアドレスを入力します。
[承認済みドメイン] フィールドに、アプリの URL のホスト名部分(
iap-example-999999.uc.r.appspot.com
など)を入力します。フィールドにホスト名を入力したら、Enter
キーを押します。[アプリケーション ホームページ リンク] フィールドに、アプリの URL(
https://iap-example-999999.uc.r.appspot.com/
など)を入力します。[Application privacy policy line] フィールドでは、テスト用にホームページ リンクと同じ URL を使用します。
[保存] をクリックします。認証情報の作成が要求されたら、ウィンドウを閉じます。
Google Cloud コンソールで、[Identity-Aware Proxy] ページに移動します。
ページを更新するには、[Refresh](更新)をクリックします。refreshページに、保護可能なリソースのリストが表示されます。
[IAP] 列でクリックしてアプリの IAP をオンにします。
ブラウザで、再度
web-site-url
にアクセスします。ウェブページの代わりに、自分を認証するためのログイン画面が表示されます。ログインしようとすると、アプリにアクセス可能なユーザーのリストが IAP にないため、アクセスが拒否されます。
アプリに承認済みユーザーを追加する
Google Cloud コンソールで、[Identity-Aware Proxy] ページに移動します。
App Engine アプリのチェックボックスをオンにしてから、[プリンシパルを追加] をクリックします。
allAuthenticatedUsers
と入力してから、[Cloud IAP/IAP で保護されたウェブアプリ ユーザー] 役割を選択します。[保存] をクリックします。
これで、Google で認証可能なすべてのユーザーがアプリにアクセスできます。必要に応じて、1 人または複数のユーザーやグループをプリンシパルとして追加するだけで、さらにアクセスを制限できます。
Gmail または Google Workspace のメールアドレス
Google グループ メールアドレス
Google Workspaceのドメイン名
アプリにアクセスする
ブラウザで、
web-site-url
にアクセスします。ページを更新するには、[更新] refresh 更新をクリックします。
ログイン画面で、Google 認証情報を使用してログインします。
ページに、メールアドレスが記載された「Hello
user-email-address
」ページが表示されます。以前と同じページが表示される場合は、IAP を有効にしたブラウザで新しいリクエストが完全に更新されない問題が発生している可能性があります。すべてのブラウザ ウィンドウを閉じてから、もう一度開いて、やり直してください。
認証のコンセプト
アプリが、そのユーザーを認証し、承認されたユーザーのみにアクセスを制限可能な方法がいくつかあります。次のセクションで、一般的な認証方法をアプリの負荷が高い順に一覧表示します。
オプション | メリット | デメリット |
---|---|---|
アプリ認証 |
|
|
OAuth2 |
|
|
IAP |
|
|
アプリ管理認証
この方法では、アプリがユーザー認証のすべての側面を独自に管理します。アプリは、ユーザー認証情報の独自のデータベースを維持してユーザー セッションを管理し、ユーザー アカウントとパスワードの管理、ユーザー認証情報のチェック、認証されたログインごとのユーザー セッションの発行、チェック、更新を行う必要があります。次の図は、アプリ管理認証方法を示しています。
図に示すように、ユーザーがログインすると、アプリがそのユーザーのセッションに関する情報を作成して維持します。ユーザーがアプリにリクエストを発行する場合は、そのリクエストにアプリが検証するセッション情報が含まれている必要があります。
このアプローチの主なメリットは、自己完結型であることと、アプリの制御下で行われることです。アプリをインターネット上で使用可能にする必要さえありません。主なデメリットは、アプリがすべてのアカウント管理機能を提供し、すべての機密性の高い認証情報データを保護する必要があることです。
OAuth2 を使用した外部認証
アプリ内ですべてを処理する代わりに、Google などの外部の ID サービスを使用して、すべてのアカウント情報と機能を処理し、機密性の高い認証情報を保護することをおすすめします。ユーザーがアプリにログインしようとすると、リクエストが ID サービスにリダイレクトされ、そこでユーザーが認証されてから、必要な認証情報と一緒にリクエストがアプリに返されます。詳しくは、Using OAuth 2.0 for Web Server Applications(英語)をご覧ください。
次の図は、OAuth2 方式を使用した外部認証を示しています。
図のフローは、ユーザーがアプリにアクセスするためのリクエストを送信するところから始まります。直接応答する代わりに、アプリは、ユーザーのブラウザを Google の Identity Platform にリダイレクトします。そこで、Google にログインするためのページが表示されます。ログインに成功すると、ユーザーのブラウザがアプリに戻されます。このリクエストには、認証されたユーザーに関してアプリが検索可能な情報が含まれており、アプリはユーザーに応答できます。
この方法には、アプリにとっての多くのメリットがあります。アプリがすべてのアカウント管理機能とリスクを外部サービスに委任することで、アプリを変更せずにログインとアカウント セキュリティを向上させることができます。ただし、上の図に示すように、この方法を使用するには、アプリからインターネットにアクセスできる必要があります。また、アプリには、ユーザーの認証後にセッションを管理する責任があります。
Identity-Aware Proxy
このチュートリアルで扱う 3 つ目のアプローチは、IAP を使用して、認証とアプリに対するなんらかの変更を伴うセッション管理をすべて処理する方法です。IAP は、アプリへのすべてのウェブ リクエストを傍受して、認証されていないリクエストをブロックし、それ以外のリクエストはリクエストごとにユーザー ID データを追加してアプリに渡します。
リクエストの処理を次の図に示します。
ユーザーからの要求は、IAP によって傍受され、認証されていない要求がブロックされます。認証されたユーザーが許可されたユーザーのリストに含まれている場合は、認証されたリクエストがアプリに渡されます。IAP を介して渡されたリクエストには、要求を行ったユーザーを識別するヘッダーが追加されます。
アプリは、ユーザー アカウントやセッション情報を処理する必要がなくなります。ユーザーの一意の識別子を知る必要があるオペレーションでは、受信ウェブ リクエストから直接取得できます。ただし、App Engine やロードバランサなど、IAP をサポートするコンピューティング サービスでのみ使用できます。ローカル開発マシンで IAP を使用することはできません。
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.