このページでは、Identity-Aware Proxy(IAP)で保護されたリソースをユーザー アカウントまたはサービス アカウントから認証する方法について説明します。
ユーザー アカウントは、個々のユーザーに属します。ユーザーの代わりにアプリケーションが IAP で保護されたリソースにアクセスする必要がある場合、ユーザー アカウントを認証します。詳しくは、ユーザー アカウントをご覧ください。
サービス アカウントは、個々のユーザーではなくアプリケーションに属します。アプリケーションから IAP で保護されたリソースにアクセスできるようにする場合、サービス アカウントを認証します。詳しくは、サービス アカウントをご覧ください。
始める前に
始める前に、次のものが必要になります。
- デベロッパー アカウント、サービス アカウント、モバイルアプリの認証情報を使用してプログラムで接続する、IAP で保護されたアプリケーション。
ユーザー アカウントの認証
デスクトップまたはモバイルアプリからアプリへのユーザー アクセスを有効にすると、プログラムから IAP で保護されたリソースを操作できます。
モバイルアプリからの認証
- モバイルアプリ用に OAuth 2.0 クライアント ID を作成するか、既存の OAuth 2.0 クライアント ID を使用します。既存の OAuth 2.0 クライアント ID を使用するには、OAuth クライアントを共有する方法の手順に沿って操作します。
- アプリケーションのプログラムによるアクセス用に OAuth クライアント ID を許可リストに登録します。
- IAP で保護されたクライアント ID の ID トークンを取得します。
- Android: Google Sign-In API を使用して OpenID Connect(OIDC)トークンをリクエストします。
requestIdToken
クライアント ID を接続先のリソースのクライアント ID に設定します。 - iOS: Google ログインを使用して ID トークンを取得します。
- Android: Google Sign-In API を使用して OpenID Connect(OIDC)トークンをリクエストします。
Authorization: Bearer
ヘッダーに ID トークンを含めて、IAP で保護されたリソースに認証済みリクエストを送信します。
デスクトップ アプリからの認証
このセクションでは、デスクトップ コマンドラインからユーザー アカウントを認証する方法について説明します。
- デベロッパーがコマンドラインからアプリケーションにアクセスできるようにするには、デスクトップ OAuth 2.0 クライアント ID を作成するか、既存のデスクトップ OAuth クライアント ID を共有します。
- アプリケーションのプログラムによるアクセス用に OAuth クライアント ID を許可リストに登録します。
アプリケーションへのログイン
個々のデベロッパーが IAP で保護されたアプリにアクセスするには、まずログインする必要があります。gcloud CLI を使用するなどの方法で、プロセスをスクリプトにパッケージ化できます。次に、curl を使用してログインし、アプリケーションにアクセスするために使用できるトークンを生成する例を示します。
- Google Cloud リソースにアクセスできるアカウントにログインします。
-
受信リクエストをエコーできるローカル サーバーを起動します。
注: このコマンドは NetCat ユーティリティを使用します。 任意のユーティリティを使用できます。$ nc -k -l 4444
-
下記の URI に移動します。
DESKTOP_CLIENT_ID
は、上記で作成した [デスクトップ アプリ] のクライアント ID です。https://accounts.google.com/o/oauth2/v2/auth?client_id=DESKTOP_CLIENT_ID&response_type=code&scope=openid%20email&access_type=offline&redirect_uri=http://localhost:4444&cred_ref=true
-
ローカル サーバーの出力で、リクエスト パラメータを探します。次のようになります。
GET /?code=$CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1
コードをコピーし、以下のAUTH_CODE
を上記で作成したデスクトップ アプリのクライアント ID とシークレットに置き換えます。curl --verbose \ --data client_id=DESKTOP_CLIENT_ID \ --data client_secret=DESKTOP_CLIENT_SECRET \ --data code=AUTH_CODE \ --data redirect_uri=http://localhost:4444 \ --data grant_type=authorization_code \ https://oauth2.googleapis.com/token
このコードは、アプリケーションにアクセスするために使用できる
id_token
フィールドを含む JSON オブジェクトを返します。
アプリケーションへのアクセス
アプリにアクセスするには、次のように id_token
を使用します。
curl --verbose --header 'Authorization: Bearer ID_TOKEN' URL
トークンを更新
ログインフロー中に生成された更新トークンを使用して、新しい ID トークンを取得できます。これは、元の ID トークンが期限切れになった際に役立ちます。各 ID トークンは約 1 時間有効です。その間、特定のアプリに対して複数のリクエストを行うことができます。
次の curl を使用する例では、更新トークンを使用して新しい ID トークンを取得します。次の例では、REFRESH_TOKEN
はログインフローで生成したトークンです。DESKTOP_CLIENT_ID
と DESKTOP_CLIENT_SECRET
は、ログインフローと同じです。
curl --verbose \ --data client_id=DESKTOP_CLIENT_ID \ --data client_secret=DESKTOP_CLIENT_SECRET \ --data refresh_token=REFRESH_TOKEN \ --data grant_type=refresh_token \ https://oauth2.googleapis.com/token
このコードは、アプリにアクセスするために使用できる新しい id_token
フィールドを含む JSON オブジェクトを返します。
サービス アカウントの認証
サービス アカウント JWT または OpenID Connect(OIDC)トークンを使用して、IAP で保護されたリソースでサービス アカウントを認証できます。次の表に、さまざまな認証トークンとその機能の違いを示します。
認証機能 | サービス アカウント JWT | OpenID Connect トークン |
---|---|---|
コンテキストアウェア アクセスのサポート | ||
OAuth 2.0 クライアント ID の要件 | ||
トークンのスコープ | IAP で保護されたリソースの URL | OAuth 2.0 クライアント ID |
サービス アカウント JWT による認証
JWT を使用してサービス アカウントを認証する主な手順は次のとおりです。
呼び出し元のサービス アカウントにサービス アカウント トークン作成者のロール(
roles/iam.serviceAccountTokenCreator
)を付与します。このロールにより、プリンシパルは JWT などの有効期間の短い認証情報を作成できます。
IAP で保護されたリソースの JWT を作成します。
サービス アカウントの秘密鍵を使用して JWT に署名します。
JWT の作成
作成された JWT のペイロードは、次の例のようになります。
{ "iss": SERVICE_ACCOUNT_EMAIL_ADDRESS, "sub": SERVICE_ACCOUNT_EMAIL_ADDRESS, "aud": TARGET_URL, "iat": IAT, "exp": EXP, }
iss
フィールドとsub
フィールドに、サービス アカウントのメールアドレスを指定します。これは、サービス アカウント JSON ファイルのclient_email
フィールドにあります。または渡すこともできます。一般的な形式:service-account@PROJECT_ID.iam.gserviceaccount.com
aud
フィールドに、IAP で保護されたリソースの URL を指定します。iat
フィールドには現在の Unix エポック時刻を指定します。exp
フィールドには、3,600 秒以内の時刻を指定します。これにより、JWT の有効期限が定義されます。
JWT の署名
JWT に署名するには、次のいずれかの方法を使用します。
- IAM 認証情報 API を使用して、秘密鍵に直接アクセスしなくても JWT に署名します。
- ローカル認証情報鍵ファイルを使用して、ローカルで JWT に署名します。
IAM Service Account Credentials API を使用した JWT の署名
IAM Service Account Credentials API を使用して、サービス アカウント JWT に署名します。このメソッドは、サービス アカウントに関連付けられた秘密鍵を取得し、それを使用して JWT ペイロードに署名します。これにより、秘密鍵に直接アクセスせずに JWT に署名できます。
IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。
gcloud
次のコマンドを実行して、JWT ペイロードを含むリクエストを準備します。
cat > claim.json << EOM { "iss": "SERVICE_ACCOUNT_EMAIL_ADDRESS", "sub": "SERVICE_ACCOUNT_EMAIL_ADDRESS", "aud": "TARGET_URL", "iat": $(date +%s), "exp": $((`date +%s` + 3600)) } EOM
次の Google Cloud CLI コマンドを使用して、
request.json
でペイロードに署名します。gcloud iam service-accounts sign-jwt --iam-account=SERVICE_ACCOUNT_EMAIL_ADDRESS claim.json output.jwt
リクエストが成功すると、
output.jwt
に署名付き JWT が含まれます。JWT を使用して、IAP で保護されたリソースにアクセスします。
Python
import datetime
import json
import google.auth
from google.cloud import iam_credentials_v1
import jwt
def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
"""Generates JWT payload for service account.
The resource url provided must be the same as the url of the IAP secured resource.
Args:
service_account_email (str): Specifies service account JWT is created for.
resource_url (str): Specifies scope of the JWT, the URL that the JWT will be allowed to access.
Returns:
A signed-jwt that can be used to access IAP protected applications.
Access the application with the JWT in the Authorization Header.
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
"""
iat = datetime.datetime.now(tz=datetime.timezone.utc)
exp = iat + 3600
return json.dumps({
'iss': service_account_email,
'sub': service_account_email,
'aud': resource_url,
'iat': iat,
'exp': exp,
})
def sign_jwt(target_sa: str, resource_url: str) -> str:
"""Signs JWT payload using ADC and IAM credentials API.
Args:
target_sa (str): Service Account JWT is being created for.
iap.webServiceVersions.accessViaIap permission is required.
resource_url (str): Audience of the JWT, and scope of the JWT token.
This is the url of the IAP protected application.
Returns:
A signed-jwt that can be used to access IAP protected apps.
"""
source_credentials, _ = google.auth.default()
iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)
return iam_client.sign_jwt(
name=iam_client.service_account_path('-', target_sa),
payload=generate_jwt_payload(target_sa, resource_url),
).signed_jwt
リクエストが成功すると、スクリプトは署名付きの JWT を返します。JWT を使用して、IAP で保護されたリソースにアクセスします。
curl
次のコマンドを実行して、JWT ペイロードを含むリクエストを準備します。
cat << EOF > request.json { "payload": JWT_PAYLOAD } EOF
IAM Service Account Credentials API を使用して JWT に署名します。
curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json; charset=utf-8" \ -d @request.json \ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL_ADDRESS:signJwt"
リクエストが成功すると、署名付きの JWT がレスポンスに含まれます。
JWT を使用して、IAP で保護されたリソースにアクセスします。
ローカル認証情報鍵ファイルから JWT に署名する
JWT は、サービス アカウントの秘密鍵を使用して署名されます。
サービス アカウント キーファイルがある場合は、JWT をローカルで署名できます。
このスクリプトは、ペイロードとともに JWT ヘッダーを送信します。ヘッダーの kid
フィールドには、サービス アカウントの秘密鍵 ID を使用します。これは、サービス アカウント認証情報 JSON ファイルの private_key_id
フィールドにあります。この鍵は JWT の署名にも使用されます。
Python
import time
import jwt
import json
def generate_jwt_payload(service_account_email, resource_url):
"""Generates JWT payload for service account.
The resource url provided must be the same as the url of the IAP secured resource.
Args:
service_account_email (str): Specifies service account JWT is created for.
resource_url (str): Specifies scope of the JWT, the URL that the JWT will be allowed to access.
Returns:
A signed-jwt that can be used to access IAP protected applications.
Access the application with the JWT in the Authorization Header.
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
"""
iat = datetime.datetime.now(tz=datetime.timezone.utc)
exp = iat + 3600
return json.dumps({
'iss': service_account_email,
'sub': service_account_email,
'aud': resource_url,
'iat': iat,
'exp': exp,
})
def sign_jwt_with_key_file(credential_key_file_path, resource_url):
"""Signs JWT payload using local service account credential key file.
Args:
credential_key_file_path (str): Path to the downloaded JSON credentials of the service
account the JWT is being created for.
resource_url (str): Scope of JWT token, This is the url of the IAP protected application.
Returns:
A service account JWT created with a downloaded private key.
"""
with open(credential_key_file_path, 'r') as credential_key_file:
key_data = json.load(credential_key_file)
PRIVATE_KEY_ID_FROM_JSON = key_data["private_key_id"]
PRIVATE_KEY_FROM_JSON = key_data["private_key"]
SERVICE_ACCOUNT_EMAIL = key_data["client_email"]
# Sign JWT with private key and store key id in the header
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
payload = generate_jwt_payload(service_account_email=SERVICE_ACCOUNT_EMAIL, resource_url=resource_url)
signed_jwt = jwt.encode(
payload,
PRIVATE_KEY_FROM_JSON,
headers=additional_headers,
algorithm='RS256',
)
return signed_jwt
署名付き JWT が生成されます。
アプリケーションへのアクセス
いずれの場合も、アプリにアクセスするには、次のように signed-jwt
を使用します。
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
OIDC トークンによる認証
- 既存の OAuth 2.0 クライアント ID を作成するか、使用します。既存の OAuth 2.0 クライアント ID を使用するには、OAuth クライアントの共有方法の手順に沿って操作してください。
- アプリケーションのプログラムによるアクセス用に OAuth クライアント ID を許可リストに登録します。
また、IAP で保護されたプロジェクトのアクセスリストにサービス アカウントを追加する必要もあります。次のコードサンプルは、OIDC トークンを取得する方法を示しています。IAP で保護されたリソースへの認証リクエストを送信するには、Authorization: Bearer
ヘッダーにトークンを含める必要があります。
デフォルトのサービス アカウント用に OIDC トークンを取得する
Compute Engine、App Engine、Cloud Run のデフォルトのサービス アカウント用 OIDC トークンを取得する場合は、以下のコードサンプルを使用してアクセス トークンを生成し、IAP で保護されたリソースにアクセスします。
C#
Go
IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。
Java
Node.js
PHP
IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。
Python
IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。
Ruby
IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。
ローカルのサービス アカウント キー ファイルから OIDC トークンを取得する
サービス アカウント キー ファイルがある場合は、上記のサンプルコードでサービス アカウント キー ファイルを指定できます。
Bash
#!/usr/bin/env bash
set -euo pipefail
get_token() {
# Get the bearer token in exchange for the service account credentials.
local service_account_key_file_path="${1}"
local iap_client_id="${2}"
local iam_scope="https://www.googleapis.com/auth/iam"
local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"
local private_key_id="$(cat "${service_account_key_file_path}" | jq -r '.private_key_id')"
local client_email="$(cat "${service_account_key_file_path}" | jq -r '.client_email')"
local private_key="$(cat "${service_account_key_file_path}" | jq -r '.private_key')"
local issued_at="$(date +%s)"
local expires_at="$((issued_at + 600))"
local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
local header_base64="$(echo "${header}" | base64)"
local payload="{'iss':'${client_email}','aud':'${oauth_token_uri}','exp':${expires_at},'iat':${issued_at},'sub':'${client_email}','target_audience':'${iap_client_id}'}"
local payload_base64="$(echo "${payload}" | base64)"
local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}") | base64)"
local assertion="${header_base64}.${payload_base64}.${signature_base64}"
local token_payload="$(curl -s \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
--data-urlencode "assertion=${assertion}" \
https://www.googleapis.com/oauth2/v4/token)"
local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
echo "${bearer_id_token}"
}
main(){
# TODO: Replace the following variables:
SERVICE_ACCOUNT_KEY="service_account_key_file_path"
IAP_CLIENT_ID="iap_client_id"
URL="application_url"
# Obtain the ID token.
ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")
# Access the application with the ID token.
curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
}
main "$@"
OIDC トークンを取得するほかのケース
上記以外の場合は、IAP で保護されたリソースにアクセスする直前に IAM 認証情報 API を使用し、ターゲット サービス アカウントになりすまして OIDC トークンを生成します。このプロセスには、次のステップが含まれます。
呼び出し側のサービス アカウント(ID トークンを取得するコードに関連付けられたサービス アカウント)に、サービス アカウントの OpenID Connect ID トークン作成者ロール(
roles/iam.serviceAccountOpenIdTokenCreator
)を付与します。これにより、呼び出し元のサービス アカウントが、ターゲット サービス アカウントの権限を借用できるようになります。
呼び出し側のサービス アカウントが提供する認証情報を使用して、ターゲット サービス アカウントの generateIdToken メソッドを呼び出します。
audience
フィールドにクライアント ID を設定します。
手順については、ID トークンを作成するをご覧ください。
Proxy-Authorization ヘッダーからの認証
アプリケーションが Authorization
リクエスト ヘッダーを使用する場合は、代わりに Proxy-Authorization: Bearer
ヘッダーに ID トークンを含めることができます。有効な ID トークンが Proxy-Authorization
ヘッダーで見つかった場合、IAP はそのトークンを使用してリクエストを承認します。リクエストを承認すると、IAP はコンテンツを処理せずに Authorization
ヘッダーをアプリケーションに渡します。
Proxy-Authorization
ヘッダーに有効な ID トークンが見つからない場合、IAP は Authorization
ヘッダーの処理を続行し、Proxy-Authorization
ヘッダーを削除してから、リクエストをアプリケーションに渡します。
次のステップ
- Authorization: Bearer トークンの詳細を確認する。
- Android 用のログインまたは iOS 用のログインを試す。