程式輔助驗證

本頁面說明如何利用使用者帳戶或服務帳戶驗證受 Identity-Aware Proxy (IAP) 保護的資源。

程式存取權是指從非瀏覽器用戶端呼叫 IAP 保護應用程式的情況。包括指令列工具、服務對服務呼叫和行動應用程式。視用途而定,您可能會想使用使用者憑證或服務憑證,向 IAP 進行驗證。

  • 「使用者帳戶」屬於個別使用者。當您的應用程式需要代表使用者存取受 IAP 保護的資源時,您可以驗證使用者帳戶。詳情請參閱「使用者帳戶」。

  • 「服務帳戶」代表的是應用程式,而非個別使用者。當您想讓應用程式存取受 IAP 保護的資源時,您可以驗證服務帳戶。詳情請參閱「服務帳戶」。

IAP 支援下列類型的憑證,以便程式輔助存取:

  • OAuth 2.0 ID 權杖:Google 為真實使用者或服務帳戶核發的權杖,其中目標對象宣告設為 IAP 應用程式的資源 ID。
  • 服務帳戶簽署的 JWT:服務帳戶的自行簽署或 Google 核發的 JWT 權杖。

AuthorizationProxy-Authorization HTTP 標頭中,將這些憑證傳遞給 IAP。

事前準備

開始操作前,您需要一個受 IAP 保護的應用程式,並且要使用開發人員帳戶、服務帳戶或行動應用程式憑證,以程式化方式連線至該應用程式。

驗證使用者帳戶

您可以讓使用者從電腦或行動裝置存取您的應用程式,以讓程式與受 IAP 保護的資源互動。

透過行動應用程式驗證

  1. 建立或使用行動應用程式的現有 OAuth 2.0 用戶端 ID。如要使用現有的 OAuth 2.0 用戶端 ID,請按照「如何共用 OAuth 用戶端」中的步驟操作。將 OAuth 用戶端 ID 新增至應用程式的程式碼存取權許可清單。
  2. 針對受 IAP 保護的用戶端 ID,取得 ID 符記。
  3. 將 ID 符記包含在 Authorization: Bearer 標頭中,以對受 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,以及 Desktop 應用程式 的用戶端 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 權杖的有效期約為一個小時,在此期間,您可以對特定應用程式提出多次要求。

以下範例使用 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 物件,您可以使用該欄位存取應用程式。

驗證服務帳戶

您可以使用服務帳戶 JWTOpenID Connect (OIDC) 憑證,透過 IAP 保護的資源驗證服務帳戶。下表列出不同驗證權杖和其功能之間的部分差異。

驗證功能 服務帳戶 JWT OpenID Connect 權杖
情境感知存取權支援
OAuth 2.0 用戶端 ID 規定
符記範圍 IAP 保護資源的網址 OAuth 2.0 用戶端 ID

使用服務帳戶 JWT 進行驗證

IAP 支援服務帳戶 JWT 驗證,適用於已設定 Google 身分、Identity Platform 和 Workforce Identity 聯盟的應用程式。

使用 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,
}
  • isssub 欄位中,指定服務帳戶的電子郵件地址。您可以在服務帳戶 JSON 檔案的 client_email 欄位中找到這個值,或透過該值傳入。一般格式: service-account@PROJECT_ID.iam.gserviceaccount.com

  • 針對 aud 欄位,請指定 IAP 安全性保護的資源網址。

  • 針對 iat 欄位,請指定目前的 Unix 紀元時間,針對 exp 欄位,請指定 3600 秒後的時間。這會定義 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,您可以使用該 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,該 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. 建立包含必要欄位的 JWT,包括用作目標對象的 IAP 用戶端 ID
  3. 使用服務帳戶的私密金鑰簽署 JWT
  4. 透過 Google 的 OAuth 服務,將此 JWT 換成 OIDC 權杖
  5. 使用產生的權杖,向受 IAP 保護的資源提出已驗證的要求

如何使用這個指令碼:

  1. 將其儲存到檔案中,例如:get_iap_token.sh
  2. 將其設為可執行:chmod +x get_iap_token.sh
  3. 使用三個參數執行它:
  ./get_iap_token.sh service-account-key.json \
    OAUTH_CLIENT_ID \
    URL

其中:

  • service-account-key.json 是您下載的服務帳戶金鑰檔案
  • OAUTH_CLIENT_ID 是 IAP 安全資源的 OAuth 用戶端 ID
  • URL 是您要存取的網址

在其他情況下取得 OIDC 權杖

在其他所有情況下,請使用 IAM 憑證 API 產生 OIDC 權杖,方法是在存取受 IAP 保護的資源之前,冒用目標服務帳戶。這項程序包含下列步驟:

  1. 為呼叫的服務帳戶 (與取得 ID 權杖的程式碼相關聯的服務帳戶) 提供服務帳戶 OpenID Connect 身分識別權杖建立者角色 (roles/iam.serviceAccountOpenIdTokenCreator)。

    這可讓呼叫服務帳戶模擬目標服務帳戶。

  2. 使用呼叫服務帳戶提供的憑證,在目標服務帳戶上呼叫 generateIdToken 方法。

    audience 欄位設為用戶端 ID。

如需逐步操作說明,請參閱「建立 ID 權杖」。

透過 Proxy-Authorization 標頭驗證

如果應用程式使用 Authorization 要求標頭,您可以改為在 Proxy-Authorization: Bearer 標頭中加入 ID 權杖。如果 Proxy-Authorization 標頭中找到有效的 ID 權杖,IAP 就會使用該權杖授權要求。授權要求後,IAP 會將 Authorization 標頭傳遞至應用程式,但不會處理內容。

如果 Proxy-Authorization 標頭中找不到有效的 ID 權杖,IAP 會繼續處理 Authorization 標頭,並在將要求傳送至應用程式前移除 Proxy-Authorization 標頭。

後續步驟