プログラムによる認証

このドキュメントでは、IAP で保護されたリソースをユーザー アカウントまたはサービス アカウントから認証する方法について説明します。

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

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

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

IAP は、プログラムによるアクセスに対して次のタイプの認証情報をサポートしています。

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

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

始める前に

  1. デベロッパー アカウント、サービス アカウント、モバイルアプリの認証情報を使用してプログラムでアクセスするアプリケーションがあることを確認します。

  2. 1 つ以上の OAuth 2.0 クライアントを作成するには、プログラムによるアクセスをご覧ください。

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

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

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

  1. モバイルアプリ用の OAuth 2.0 クライアント ID を作成するか、既存の OAuth 2.0 クライアント ID を使用します。既存の OAuth 2.0 クライアント ID を使用するには、OAuth クライアントを共有する方法の手順に沿って操作します。アプリケーションへのプログラムによるアクセスの許可リストに OAuth クライアント ID を追加します。
  2. IAP で保護されたリソースの OAuth 2.0 クライアント 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 を、デスクトップ アプリのクライアント 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 またはパス ワイルドカード(/*)を含む URL(https://example.com/https://example.com/* など)を指定します。aud フィールドに正確な URL を含む JWT は、その特定の URL にのみアクセスできます。aud フィールドにパス ワイルドカード(/*)を含む JWT は、末尾の * がない aud 文字列で始まるすべての 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 には、IAP で保護されたリソースへのアクセスに使用できる署名付き JWT が含まれます。

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 the service account that the
        JWT is created for.
        resource_url (str): Specifies the 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-secured application.

    Returns:
        str: A signed JWT that can be used to access IAP-secured applications.
            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.
    # Project should always be "-".
    # Replacing the wildcard character with a project ID is invalid.
    name = iam_client.service_account_path("-", 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 にローカルで署名する場合は、ペイロードを含む JWT ヘッダーを含めます。ヘッダーの kid フィールドには、サービス アカウントの秘密鍵 ID を使用します。これは、サービス アカウント認証情報 JSON ファイルの private_key_id フィールドにあります。ファイルから取得した秘密鍵を使用して JWT に署名します。

アプリケーションにアクセスする

アプリケーションにアクセスするには、署名付き JWT を Authorization ヘッダーに含めます。

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

サービス アカウントの OIDC トークンで認証する

サービス アカウントの OIDC トークンで認証するには、次の操作を行います。

  1. 新しい OIDC クライアント ID を作成するか、既存の OIDC クライアント ID を使用します。

    • 新しい OAuth 2.0 クライアント ID を作成するには、次の操作を行います

      1. まだ登録していない場合は、Google Auth を使用するようにアプリケーションを登録します。

      2. Google Auth Platform のページに移動します。

        Google Auth Platform に移動

        プロジェクトが選択されていない場合は、プロジェクトの作成を求めるメッセージが表示されます。

      3. [クライアントを作成] をクリックします。

      4. 適切な申請タイプを選択し、必要に応じて追加情報を入力します。

      5. 選択したクライアント タイプに必要な情報を入力します。クライアントを作成するには、[作成] をクリックします。

    • 既存の 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