プログラムによる認証

このページでは、Identity-Aware Proxy(IAP)で保護されたリソースをユーザー アカウントまたはサービス アカウントから認証する方法について説明します。

プログラムによるアクセスは、ブラウザ以外のクライアントから IAP で保護されたアプリケーションを呼び出すシナリオです。これには、コマンドライン ツール、サービス間呼び出し、モバイル アプリケーションが含まれます。ユースケースに応じて、ユーザー認証情報またはサービス認証情報を使用して IAP の認証を行う場合があります。

  • ユーザー アカウントは、個々のユーザーに属します。ユーザーの代わりにアプリケーションが IAP で保護されたリソースにアクセスする必要がある場合、ユーザー アカウントを認証します。詳しくは、ユーザー アカウントをご覧ください。

  • サービス アカウントは、個々のユーザーではなくアプリケーションを表します。アプリケーションから IAP で保護されたリソースにアクセスできるようにする場合、サービス アカウントを認証します。詳細については、サービス アカウントをご覧ください。

IAP は、プログラマティック アクセス用の次のタイプの認証情報をサポートしています。

  • OAuth 2.0 ID トークン - 人間のユーザーまたはサービス アカウント用の Google 発行トークン。対象クレームが IAP アプリケーションのリソース ID に設定されています。
  • サービス アカウントで署名された JWT - サービス アカウントの自己署名または Google 発行の JWT トークン。

これらの認証情報を Authorization または Proxy-Authorization HTTP ヘッダーで IAP に渡します。

始める前に

始める前に、デベロッパー アカウント、サービス アカウント、モバイルアプリの認証情報を使用してプログラムで接続する、IAP で保護されたアプリケーションが必要です。

ユーザー アカウントを認証する

デスクトップまたはモバイルアプリからアプリへのユーザー アクセスを有効にすると、プログラムから IAP で保護されたリソースを操作できます。

モバイルアプリから認証する

  1. モバイルアプリ用に OAuth 2.0 クライアント ID を作成するか、既存の OAuth 2.0 クライアント ID を使用します。既存の OAuth 2.0 クライアント ID を使用するには、OAuth クライアントを共有する方法の手順に沿って操作してください。アプリケーションのプログラムによるアクセス用に、OAuth クライアント ID を許可リストに追加します。
  2. IAP で保護されたクライアント ID の ID トークンを取得します。
  3. Authorization: Bearer ヘッダーに ID トークンを含めて、IAP で保護されたリソースに認証済みリクエストを送信します。

デスクトップ アプリからの認証

このセクションでは、デスクトップ コマンドラインからユーザー アカウントを認証する方法について説明します。

  1. デベロッパーがコマンドラインからアプリケーションにアクセスできるようにするには、デスクトップ OAuth 2.0 クライアント ID を作成するか、既存のデスクトップ OAuth クライアント ID を共有します。
  2. アプリケーションのプログラムによるアクセス用に、OAuth ID を許可リストに追加します。

アプリケーションにログインする

個々のデベロッパーが IAP で保護されたアプリにアクセスするには、まずログインする必要があります。gcloud CLI を使用するなどの方法で、プロセスをスクリプトにパッケージ化できます。次の例では、curl を使用してログインし、アプリケーションにアクセスするために使用できるトークンを生成します。

  1. リソースにアクセスできるアカウントにログインします。 Google Cloud
  2. 受信リクエストをエコーできるローカル サーバーを起動します。

      # Example using Netcat (http://netcat.sourceforge.net/)
      nc -k -l 4444
    
  3. 次の 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
    
  4. ローカル サーバーの出力で、リクエスト パラメータを探します。

      GET /?code=CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1
    
  5. CODE 値をコピーし、次のコマンドの AUTH_CODE と、デスクトップ アプリのクライアント ID とシークレットに置き換えます。

      curl --verbose \
        --data client_id=DESKTOP_CLIENT_ID \
        --data client_secret=DESKTOP_CLIENT_SECRET \
        --data code=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_IDDESKTOP_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 で認証する

IAP は、Google ID、Identity Platform、Workforce Identity Federation で構成されたアプリケーションのサービス アカウント JWT 認証をサポートしています。

JWT を使用してサービス アカウントを認証する主な手順は次のとおりです。

  1. 呼び出し元のサービス アカウントにサービス アカウント トークン作成者ロール(roles/iam.serviceAccountTokenCreator)を付与します。

    このロールにより、プリンシパルは JWT などの有効期間の短い認証情報を作成できます。

  2. IAP で保護されたリソースの JWT を作成します。

  3. サービス アカウントの秘密鍵を使用して 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

  1. 次のコマンドを実行して、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
  1. 次の Google Cloud CLI コマンドを使用して、claim.json でペイロードに署名します。
gcloud iam service-accounts sign-jwt --iam-account="SERVICE_ACCOUNT_EMAIL_ADDRESS" claim.json output.jwt

リクエストが成功すると、output.jwt に署名付き JWT が含まれ、IAP で保護されたリソースへのアクセスに使用できます。

Python

import datetime
import json

import google.auth
from google.cloud import iam_credentials_v1

def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
    """Generates JWT payload for service account.

    Creates a properly formatted JWT payload with standard claims (iss, sub, aud,
    iat, exp) needed for IAP authentication.

    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:
        str: JSON string containing the JWT payload with properly formatted claims.
    """
    # Create current time and expiration time (1 hour later) in UTC
    iat = datetime.datetime.now(tz=datetime.timezone.utc)
    exp = iat + datetime.timedelta(seconds=3600)

    # Convert datetime objects to numeric timestamps (seconds since epoch)
    # as required by JWT standard (RFC 7519)
    payload = {
        "iss": service_account_email,
        "sub": service_account_email,
        "aud": resource_url,
        "iat": int(iat.timestamp()),
        "exp": int(exp.timestamp()),
    }

    return json.dumps(payload)

def sign_jwt(target_sa: str, resource_url: str) -> str:
    """Signs JWT payload using ADC and IAM credentials API.

    Uses Google Cloud's IAM Credentials API to sign a JWT. This requires the
    caller to have iap.webServiceVersions.accessViaIap permission on the target
    service account.

    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:
        str: A signed JWT that can be used to access IAP protected apps.
            Use in Authorization header as: 'Bearer <signed_jwt>'
    """
    # Get default credentials from environment or application credentials
    source_credentials, project_id = google.auth.default()

    # Initialize IAM credentials client with source credentials
    iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)

    # Generate the service account resource name
    # If project_id is None, use '-' as placeholder as per API requirements
    project = project_id if project_id else "-"
    name = iam_client.service_account_path(project, target_sa)

    # Create and sign the JWT payload
    payload = generate_jwt_payload(target_sa, resource_url)

    # Sign the JWT using the IAM credentials API
    response = iam_client.sign_jwt(name=name, payload=payload)

    return response.signed_jwt

curl

  1. 次のコマンドを実行して、JWT ペイロードを含むリクエストを準備します。

    cat << EOF > request.json
    {
      "payload": JWT_PAYLOAD
    }
    EOF
    
  2. IAM を使用して JWT に署名する

    Service Account Credentials API:

    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 がレスポンスで返されます。

  3. JWT を使用して、IAP で保護されたリソースにアクセスします。

ローカル認証情報鍵ファイルから JWT に署名する

JWT は、サービス アカウントの秘密鍵を使用して署名されます。

サービス アカウント キー ファイルがある場合は、JWT をローカルで署名できます。

このスクリプトは、ペイロードとともに JWT ヘッダーを送信します。ヘッダーの kid フィールドには、サービス アカウントの秘密鍵 ID を使用します。これは、サービス アカウント認証情報 JSON ファイルの private_key_id フィールドにあります。この鍵は JWT の署名にも使用されます。

アプリケーションへのアクセス

いずれの場合も、アプリにアクセスするには signed-jwt を使用します。

curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL

OIDC トークンによる認証

  1. 既存の OAuth 2.0 クライアント ID を作成するか、使用します。既存の OAuth 2.0 クライアント ID を使用するには、OAuth クライアントの共有方法の手順に沿って操作してください。
  2. アプリケーションのプログラムによるアクセス用に、OAuth ID を許可リストに追加します。
  3. デフォルトのサービス アカウントが IAP で保護されたプロジェクトのアクセスリストに追加されていることを確認します。

IAP で保護されたリソースにリクエストを送信する場合は、Authorization ヘッダーにトークンを含める必要があります。Authorization: 'Bearer OIDC_TOKEN'

次のコードサンプルは、OIDC トークンを取得する方法を示しています。

デフォルトのサービス アカウント用に OIDC トークンを取得する

Compute Engine、App Engine、Cloud Run のデフォルトのサービス アカウント用 OIDC トークンを取得するには、次のコードサンプルを参照して、IAP で保護されたリソースにアクセスするためのトークンを生成します。

C#

IAP で認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。


using Google.Apis.Auth.OAuth2;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

public class IAPClient
{
    /// <summary>
    /// Makes a request to a IAP secured application by first obtaining
    /// an OIDC token.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="uri">HTTP URI to fetch.</param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<HttpResponseMessage> InvokeRequestAsync(
        string iapClientId, string uri, CancellationToken cancellationToken = default)
    {
        // Get the OidcToken.
        // You only need to do this once in your application
        // as long as you can keep a reference to the returned OidcToken.
        OidcToken oidcToken = await GetOidcTokenAsync(iapClientId, cancellationToken);

        // Before making an HTTP request, always obtain the string token from the OIDC token,
        // the OIDC token will refresh the string token if it expires.
        string token = await oidcToken.GetAccessTokenAsync(cancellationToken);

        // Include the OIDC token in an Authorization: Bearer header to 
        // IAP-secured resource
        // Note: Normally you would use an HttpClientFactory to build the httpClient.
        // For simplicity we are building the HttpClient directly.
        using HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await httpClient.GetAsync(uri, cancellationToken);
    }

    /// <summary>
    /// Obtains an OIDC token for authentication an IAP request.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<OidcToken> GetOidcTokenAsync(string iapClientId, CancellationToken cancellationToken)
    {
        // Obtain the application default credentials.
        GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(cancellationToken);

        // Request an OIDC token for the Cloud IAP-secured client ID.
       return await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience(iapClientId), cancellationToken);
    }
}

Go

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

import (
	"context"
	"fmt"
	"io"
	"net/http"

	"google.golang.org/api/idtoken"
)

// makeIAPRequest makes a request to an application protected by Identity-Aware
// Proxy with the given audience.
func makeIAPRequest(w io.Writer, request *http.Request, audience string) error {
	// request, err := http.NewRequest("GET", "http://example.com", nil)
	// audience := "IAP_CLIENT_ID.apps.googleusercontent.com"
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, audience)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %w", err)
	}

	response, err := client.Do(request)
	if err != nil {
		return fmt.Errorf("client.Do: %w", err)
	}
	defer response.Body.Close()
	if _, err := io.Copy(w, response.Body); err != nil {
		return fmt.Errorf("io.Copy: %w", err)
	}

	return nil
}

Java

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.Collections;

public class BuildIapRequest {
  private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";

  private static final HttpTransport httpTransport = new NetHttpTransport();

  private BuildIapRequest() {}

  private static IdTokenProvider getIdTokenProvider() throws IOException {
    GoogleCredentials credentials =
        GoogleCredentials.getApplicationDefault().createScoped(Collections.singleton(IAM_SCOPE));

    Preconditions.checkNotNull(credentials, "Expected to load credentials");
    Preconditions.checkState(
        credentials instanceof IdTokenProvider,
        String.format(
            "Expected credentials that can provide id tokens, got %s instead",
            credentials.getClass().getName()));

    return (IdTokenProvider) credentials;
  }

  /**
   * Clone request and add an IAP Bearer Authorization header with ID Token.
   *
   * @param request Request to add authorization header
   * @param iapClientId OAuth 2.0 client ID for IAP protected resource
   * @return Clone of request with Bearer style authorization header with ID Token.
   * @throws IOException exception creating ID Token
   */
  public static HttpRequest buildIapRequest(HttpRequest request, String iapClientId)
      throws IOException {

    IdTokenProvider idTokenProvider = getIdTokenProvider();
    IdTokenCredentials credentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider(idTokenProvider)
            .setTargetAudience(iapClientId)
            .build();

    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(credentials);

    return httpTransport
        .createRequestFactory(httpRequestInitializer)
        .buildRequest(request.getRequestMethod(), request.getUrl(), request.getContent());
  }
}

Node.js

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const url = 'https://some.iap.url';
// const targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';

const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  console.info(`request IAP ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);
  const res = await client.fetch(url);
  console.info(res.data);
}

request().catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

PHP

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

namespace Google\Cloud\Samples\Iap;

# Imports Auth libraries and Guzzle HTTP libraries.
use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

/**
 * Make a request to an application protected by Identity-Aware Proxy.
 *
 * @param string $url The Identity-Aware Proxy-protected URL to fetch.
 * @param string $clientId The client ID used by Identity-Aware Proxy.
 */
function make_iap_request($url, $clientId)
{
    // create middleware, using the client ID as the target audience for IAP
    $middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($clientId);
    $stack = HandlerStack::create();
    $stack->push($middleware);

    // create the HTTP client
    $client = new Client([
        'handler' => $stack,
        'auth' => 'google_auth'
    ]);

    // make the request
    $response = $client->get($url);
    print('Printing out response body:');
    print($response->getBody());
}

Python

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests


def make_iap_request(url, client_id, method="GET", **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if "timeout" not in kwargs:
        kwargs["timeout"] = 90

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method,
        url,
        headers={"Authorization": "Bearer {}".format(open_id_connect_token)},
        **kwargs
    )
    if resp.status_code == 403:
        raise Exception(
            "Service account does not have permission to "
            "access the IAP-protected application."
        )
    elif resp.status_code != 200:
        raise Exception(
            "Bad response from application: {!r} / {!r} / {!r}".format(
                resp.status_code, resp.headers, resp.text
            )
        )
    else:
        return resp.text

Ruby

IAP への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

# url = "The Identity-Aware Proxy-protected URL to fetch"
# client_id = "The client ID used by Identity-Aware Proxy"
require "googleauth"
require "faraday"

# The client ID as the target audience for IAP
id_token_creds = Google::Auth::Credentials.default target_audience: client_id

headers = {}
id_token_creds.client.apply! headers

resp = Faraday.get url, nil, headers

if resp.status == 200
  puts "X-Goog-Iap-Jwt-Assertion:"
  puts resp.body
else
  puts "Error requesting IAP"
  puts resp.status
  puts resp.headers
end

ローカルのサービス アカウント キー ファイルから OIDC トークンを取得する

サービス アカウント キーファイルを使用して OIDC トークンを生成するには、キーファイルを使用して JWT アサーションを作成して署名し、そのアサーションを ID トークンと交換します。次の Bash スクリプトは、このプロセスを示しています。

Bash

#!/usr/bin/env bash
#
# Example script that generates an OIDC token using a service account key file
# and uses it to access an IAP-secured resource

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}"

  # Define the scope and token endpoint
  local iam_scope="https://www.googleapis.com/auth/iam"
  local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"

  # Extract data from service account key file
  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')"

  # Set token timestamps (current time and expiration 10 minutes later)
  local issued_at="$(date +%s)"
  local expires_at="$((issued_at + 600))"

  # Create JWT header and payload
  local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
  local header_base64="$(echo "${header}" | base64 | tr -d '\n')"
  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 | tr -d '\n')"

  # Create JWT signature using the private key
  local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}")  | base64 | tr -d '\n')"
  local assertion="${header_base64}.${payload_base64}.${signature_base64}"

  # Exchange the signed JWT assertion for an ID token
  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)"

  # Extract just the ID token from the response
  local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
  echo "${bearer_id_token}"
}

main() {
  # Check if required arguments are provided
  if [[ $# -lt 3 ]]; then
    echo "Usage: $0 <service_account_key_file.json> <iap_client_id> <url>"
    exit 1
  fi

  # Assign parameters to variables
  SERVICE_ACCOUNT_KEY="$1"
  IAP_CLIENT_ID="$2"
  URL="$3"

  # Generate the ID token
  echo "Generating token..."
  ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")

  # Access the IAP-secured resource with the token
  echo "Accessing: ${URL}"
  curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
}

# Run the main function with all provided arguments
main "$@"

このスクリプトによって、次の手順が実行されます。

  1. JSON キーファイルからサービス アカウント キー情報を抽出します。
  2. ターゲット オーディエンスとして IAP クライアント ID など、必要なフィールドを含む JWT を作成します。
  3. サービス アカウントの秘密鍵を使用して JWT に署名します。
  4. Google の OAuth サービスを使用して、この JWT を OIDC トークンと交換します。
  5. 生成されたトークンを使用して、IAP で保護されたリソースに認証済みリクエストを送信します。

このスクリプトを使用するには:

  1. ファイルを保存します(例: get_iap_token.sh
  2. 実行可能にします。chmod +x get_iap_token.sh
  3. 次の 3 つのパラメータを使用して実行します。
  ./get_iap_token.sh service-account-key.json \
    OAUTH_CLIENT_ID \
    URL

ここで

  • service-account-key.json は、ダウンロードしたサービス アカウント キー ファイルです。
  • OAUTH_CLIENT_ID は、IAP で保護されたリソースの OAuth クライアント ID です。
  • URL は、アクセスする URL です。

OIDC トークンを取得するほかのケース

上記以外の場合は、IAP で保護されたリソースにアクセスする直前に IAM 認証情報 API を使用し、ターゲット サービス アカウントになりすまして OIDC トークンを生成します。このプロセスには、次のステップが含まれます。

  1. 呼び出し側のサービス アカウント(ID トークンを取得するコードに関連付けられたサービス アカウント)に、サービス アカウントの OpenID Connect ID トークン作成者ロール(roles/iam.serviceAccountOpenIdTokenCreator)を付与します。

    これにより、呼び出し元のサービス アカウントが、ターゲット サービス アカウントの権限を借用できるようになります。

  2. 呼び出し側のサービス アカウントが提供する認証情報を使用して、ターゲット サービス アカウントの generateIdToken メソッドを呼び出します。

    audience フィールドにクライアント ID を設定します。

手順については、ID トークンを作成するをご覧ください。

Proxy-Authorization ヘッダーからの認証

アプリケーションが Authorization リクエスト ヘッダーを使用する場合は、代わりに Proxy-Authorization: Bearer ヘッダーに ID トークンを含めることができます。有効な ID トークンが Proxy-Authorization ヘッダーで見つかった場合、IAP はそのトークンを使用してリクエストを承認します。リクエストを承認すると、IAP はコンテンツを処理せずに Authorization ヘッダーをアプリケーションに渡します。

Proxy-Authorization ヘッダーに有効な ID トークンが見つからない場合、IAP は Authorization ヘッダーの処理を続行し、Proxy-Authorization ヘッダーを削除してから、リクエストをアプリケーションに渡します。

次のステップ