プログラムによる認証

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

  • ユーザー アカウントは、個々のユーザーに属します。ユーザーの代わりにアプリケーションが IAP で保護されたリソースにアクセスする必要がある場合、ユーザー アカウントを認証します。ユーザー アカウント認証情報をご覧ください。
  • サービス アカウントは、個々のユーザーではなくアプリケーションに属します。アプリケーションから IAP で保護されたリソースにアクセスできるようにする場合、サービス アカウントを認証します。サービス アカウントについての説明をご覧ください。

始める前に

始める前に、次のものが必要になります。

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

ユーザー アカウントの認証

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

モバイルアプリからの認証

  1. IAP で保護されたリソースと同じプロジェクトで、モバイルアプリの OAuth 2.0 クライアント ID を作成します。
    1. [認証情報] ページに移動します。
      [認証情報] ページに移動
    2. IAP で保護されたリソースを含むプロジェクトを選択します。
    3. [認証情報を作成] をクリックし、[OAuth クライアント ID] を選択します。
    4. 認証情報を作成する [アプリケーションの種類] を選択します。
    5. 必要に応じて [名前] と [制限事項] を追加し、[作成] をクリックします。
  2. 表示される [OAuth クライアント] ウィンドウで、接続先の IAP で保護されたリソースの [クライアント ID] をメモします。
  3. IAP で保護されたクライアント ID の ID トークンを取得します。
  4. Authorization: Bearer ヘッダーに ID トークンを含めて、IAP で保護されたリソースに認証済みリクエストを送信します。

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

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

クライアント ID の設定

デベロッパーがコマンドラインからアプリケーションにアクセスできるようにするには、まず [デスクトップ アプリ] タイプの OAuth クライアント ID 認証情報を作成する必要があります。

  1. [認証情報] ページに移動します。
    [認証情報] ページに移動
  2. IAP で保護されたリソースを含むプロジェクトを選択します。
  3. [認証情報を作成] をクリックし、[OAuth クライアント ID] を選択します。
  4. [アプリケーションの種類] で [デスクトップ アプリ] を選択し、[名前] を追加して、[作成] をクリックします。
  5. 表示される [OAuth クライアント] ウィンドウで、[クライアント ID] と [クライアント シークレット] をメモします。認証情報を管理したり、デベロッパーと共有したりするには、これらをスクリプトで使用する必要があります。
  6. [認証情報] ウィンドウに、アプリケーションへのアクセスに使用するメイン クライアント ID とともに、新しい [デスクトップ アプリ] の認証情報が表示されます。

アプリケーションへのログイン

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

  1. Google Cloud リソースにアクセスできるアカウントにログインします。
  2. 下記の 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=urn:ietf:wg:oauth:2.0:oob

  3. 表示されるウィンドウで、次に示す AUTH_CODE を置き換える [認証コード] と、上記で作成した [デスクトップ アプリ] のクライアント ID とシークレットをメモします。

    curl --verbose \
          --data client_id=DESKTOP_CLIENT_ID \
          --data client_secret=DESKTOP_CLIENT_SECRET \
          --data code=AUTH_CODE \
          --data redirect_uri=urn:ietf:wg:oauth:2.0:oob \
          --data grant_type=authorization_code \
          https://oauth2.googleapis.com/token

    このコードは、アプリケーションにアクセスするためのログイン トークンとして保存できる refresh_token フィールドを含む JSON オブジェクトを返します。

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

アプリケーションにアクセスするには、ID トークンのログインフローで生成した refresh_token を交換します。ID トークンは約 1 時間有効です。その間、特定のアプリに対して複数のリクエストを行うことができます。curl を使用してトークンを使用し、アプリケーションにアクセスする例を次に示します。

  1. 以下のコードを使用します。REFRESH_TOKEN はログインフローで生成したトークン、IAP_CLIENT_ID はアプリケーションへのアクセスに使用するメイン クライアント ID、DESKTOP_CLIENT_IDDESKTOP_CLIENT_SECRET は上記のクライアント ID の設定時に作成したクライアント ID とシークレットです。

    curl --verbose \
          --data client_id=DESKTOP_CLIENT_ID \
          --data client_secret=DESKTOP_CLIENT_SECRET \
          --data refresh_token=REFRESH_TOKEN \
          --data grant_type=refresh_token \
          --data audience=IAP_CLIENT_ID \
          https://oauth2.googleapis.com/token

    このコードは、アプリにアクセスするために使用できる id_token フィールドを含む JSON オブジェクトを返します。

  2. アプリにアクセスするには、次のように id_token を使用します。

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

サービス アカウントからの認証

OpenID Connect(OIDC)トークンを使用して、IAP で保護されたリソースに対してサービス アカウントを認証します。クライアント ID を確認する手順は次のとおりです。

  1. IAP ページに移動します。
  2. アクセスするリソースを見つけて、[詳細] > [OAuth クライアントを編集] をクリックします。
    [その他] メニューで OAuth クライアントを編集する

  3. 表示される [認証情報] ページで、クライアント ID をメモします。

また、IAP で保護されたプロジェクトのアクセスリストにもサービス アカウントを追加する必要があります。次のコードサンプルは、OIDC トークンを取得する方法を示しています。どれを選択するかにかかわらず、Authorization: Bearer ヘッダーにトークンを含めて、IAP で保護されたリソースに認証済みリクエストを送信する必要があります。

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

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

C#


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="credentialsFilePath">Path to the credentials .json file
    /// downloaded from 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 credentialsFilePath, 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, credentialsFilePath, cancellationToken).ConfigureAwait(false);

        // 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).ConfigureAwait(false);

        // 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).ConfigureAwait(false);
    }

    /// <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="credentialsFilePath">Path to the credentials .json file
    /// downloaded from 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, string credentialsFilePath, CancellationToken cancellationToken)
    {
        // Read credentials from the credentials .json file.
        GoogleCredential credential = await GoogleCredential
            .FromFileAsync(credentialsFilePath, cancellationToken).ConfigureAwait(false);

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

Go

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: %v", err)
	}

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

	return nil
}

Java


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 signed JWT 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 signed jwt token.
   * @throws IOException exception creating signed JWT
   */
  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

/**
 * 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.request({url});
  console.info(res.data);
}

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

PHP

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.
 *
 * @return The response body.
 */
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
    return $client->get($url);
}

Python

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

# 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 トークンを取得するほかのケース

上記以外の場合は、IAP で保護されたリソースにアクセスする直前に、IAM Credentials API を使用し、別のサービス アカウントのアクセス トークンに基づいて OIDC トークンを生成します。

  1. 対象のアカウントに対する service account token creator というロールを、アクセス トークンのアカウントに追加します。これにより、対象のサービス アカウントの OIDC トークンを作成するために必要な IAM 権限が付与されることになります。
  2. アクセス トークンを使用して、対象のサービス アカウントで generateIdToken を呼び出します。audience フィールドにクライアント ID を設定する場合は特に注意が必要です。

次のステップ