JSON ウェブトークンの認証

ベクトル検索は、自己署名 JSON Web Token(JWT)を使用して認証済みインデックス エンドポイントをサポートします。インデックス エンドポイントへのアクセスを制御するために、特別に承認された Google サービス アカウントによって発行された署名付き JWT のみを受け入れるように構成されています。つまり、指定されたアカウントを使用するクライアントのみが、エンドポイントと通信できます。

このページでは、JSON ウェブトークン(JWT)認証を使用してインデックス エンドポイントを設定し、それに対してクエリを実行するために必要な手順について説明します。

制限事項

  • JWT 認証は、VPC ピアリングまたは Private Service Connect(PSC)を使用するプライベート エンドポイントでのみサポートされます。
  • JWT 認証は、gRPC を使用して呼び出されるデータプレーン RPC API(MatchService など)でのみサポートされます。このページの RPC の例では、オープンソースの grpc_cli ツールを使用して、デプロイされたインデックス サーバーに gRPC リクエストを送信します。
  • インデックスの作成、デプロイ、管理用の Admin API は、事前定義された IAM ロールを使用して保護されています。

インデックスに対してクエリを実行する JWT の作成と使用

インデックス エンドポイントを作成し、自己署名 JWT を使用してクエリを実行する手順は次のとおりです。

インデックスの作成

インデックスを作成するの手順に沿って、ベクトル検索インデックスを作成します。

プライベート エンドポイントを作成する

次のいずれかのドキュメント ページの手順に沿って、プライベート エンドポイントを作成します。

サービス アカウントを作成する

サービス アカウントを作成し、サービス アカウント トークン作成者の IAM ロールを付与します。

  1. IAM Service Account Credentials API を有効にして、サービス アカウントを作成します。

    gcloud services enable iamcredentials.googleapis.com --project="PROJECT_ID"
    gcloud iam service-accounts create SERVICE_ACCOUNT_ID --project="PROJECT_ID"
    

    次の値を置き換えます。

    • PROJECT_ID: サービス アカウントを作成するプロジェクト。
    • SERVICE_ACCOUNT_ID: サービス アカウントの ID。

    詳しくは、サービス アカウントの作成をご覧ください。

  2. 次のいずれかのコマンドを使用して、サービス アカウントに iam.serviceAccountTokenCreator IAM ロールを付与します。

    • 次のコマンドにより、サービス アカウントが接続されている Compute Engine VM からサービス アカウントを使用して JWT を作成する権限が付与されます。

      gcloud iam service-accounts add-iam-policy-binding \
         "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
         --role "roles/iam.serviceAccountTokenCreator" \
         --member "serviceAccount:SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
         --project "PROJECT_ID"
      

      次の値を置き換えます。

      • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
      • PROJECT_ID: サービス アカウントを作成するプロジェクト。
    • 次のコマンドにより、自分の Google アカウント(ワークステーション上)からサービス アカウントを使用して JWT を作成する権限が付与されます。

      gcloud iam service-accounts add-iam-policy-binding \
         "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
         --role "roles/iam.serviceAccountTokenCreator" \
         --member "user:EMAIL_ADDRESS" \
         --project PROJECT_ID
      

      次の値を置き換えます。

      • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
      • PROJECT_ID: サービス アカウントを作成するプロジェクト。
      • EMAIL_ADDRESS: メールアドレス。

JWT 認証構成を使用してインデックスをエンドポイントにデプロイする

  1. 次の例に示すとおり、インデックスをプライベート エンドポイントにデプロイします。

    gcloud ai index-endpoints deploy-index INDEX_ENDPOINT_ID \
       --index=INDEX_ID \
       --deployed-index-id=DEPLOYED_INDEX_ID \
       --display-name=DEPLOYED_INDEX_NAME \
       --audiences=AUDIENCES \
       --allowed-issuers="SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
       --project=PROJECT_ID \
       --region=LOCATION
    

    次の値を置き換えます。

    • INDEX_ENDPOINT_ID: インデックス エンドポイントの ID。
    • INDEX_ID: インデックスの ID。
    • DEPLOYED_INDEX_ID: デプロイされたインデックスを一意に識別するユーザー指定の文字列。先頭は英字にします。英字、数字、アンダースコアのみ使用できます。形式のガイドラインについては、DeployedIndex.id をご覧ください。
    • DEPLOYED_INDEX_NAME: デプロイされたインデックスの表示名。
    • AUDIENCES: サービス、ワークロード、またはアプリの想定オーディエンスを識別するわかりやすい文字列(例: "123456-my-app")。
    • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
    • PROJECT_ID: Google Cloud プロジェクト ID
    • LOCATION: Vertex AI を使用するリージョン。

自己署名 JWT を使用してインデックスに対しクエリを実行する

大まかに言うと、必要な手順は次のとおりです。

  1. JWT ペイロードを作成します。
  2. 先に作成したサービス アカウントを使用してトークンに署名します。
  3. gRPC 呼び出しを使用してインデックスをクエリし、トークンを認証ヘッダーで渡します。

Python

JWT ペイロードを作成して署名する

この例では、Python IAM API 認証情報ライブラリの sign_jwt メソッドを使用して、署名付きトークンを取得します。このライブラリのインストール方法と使用方法については、IAM API クライアント ライブラリのドキュメントをご覧ください。

   from google.cloud import iam_credentials_v1
   from datetime import datetime, timezone
   import json

   def sign_jwt(issuer: str, audience: str):
      client = iam_credentials_v1.IAMCredentialsClient()
      payload = {
            'aud': audience,
            'sub': audience,
            'iss': issuer,
            'iat': int(datetime.now(timezone.utc).timestamp()),
            'exp': int(datetime.now(timezone.utc).timestamp()) + 600,
      }
      response = client.sign_jwt(name="projects/-/serviceAccounts/" + issuer,
                                 payload=json.dumps(payload))
      return response.signed_jwt

   sign_jwt("SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com",
            "AUDIENCES")

コマンドライン

JWT ペイロードを作成する

ベクトル検索認証は、事前定義されたオーディエンスについて、事前承認されたサービス アカウントで署名された JWT を受け入れます。インデックスをプライベート エンドポイントにデプロイするときに、サービス アカウントとオーディエンスを呼び出し元が指定する必要があります。この設定でインデックスがデプロイされると、そのエンドポイントへのすべての gRPC API リクエストには、発行元(サービス アカウント)によって署名され、指定のオーディエンスを対象とした JWT を含む認証ヘッダーを含める必要があります。署名付き JWT は、gRPC リクエストの authorization ヘッダーで署名なしトークンとして渡されます。JWT には、サービス アカウントで署名されるだけでなく、次のクレームが含まれている必要があります。

  • iss(許可されている発行者)クレームは、サービス アカウントのメールアドレスにする必要があります。次に例を示します。

    "iss": "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com"
    
  • aud(オーディエンス)クレームと sub(サブジェクト)クレームを、どちらも同じ値に設定する必要があります。これは、サービス、ワークロード、アプリの想定オーディエンスを識別するわかりやすい文字列です。次に例を示します。

    "aud": "123456-my-app",
    "sub": "123456-my-app"
    

    この値は、インデックスのデプロイ時に渡された --audiences 引数と一致する必要があります。

  • iat(発行時)クレームは、トークンが発行された時刻に設定する必要があります。exp(有効期限)クレームは少し後(約 1 時間)に設定する必要があります。これらの値は、次のように Unix エポックタイムで表されます。

    "iat": 1698966927, // unix time since epoch eg via date +%s
    "exp": 1698967527 // iat + a few mins (eg 600 seconds)
    

次の例は、単一の JWT ペイロード内のこれらのクレームを示しています。

{
   "iss": "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com",
   "aud": "123456-my-app",
   "sub": "123456-my-app",
   "iat": 1698956084,
   "exp": 1698960084
}

JWT ペイロードは、iss クレームで指定されたサービス アカウントを使用して署名されます。

JWT を作成する

  1. 呼び出し元が、サービス アカウントに対する roles/iam.serviceAccountTokenCreator ロールを使用できることを確認します。

  2. 未加工の JWT を含む jwt_in.json という名前の JSON ファイルを作成します。

    SA="serviceAccount:SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com"
    cat << EOF > jwt_in.json
    {
      "aud": "AUDIENCES",
      "sub": "AUDIENCES",
      "iss": "${SA}",
      "iat": $(date +%s),
      "exp": $(expr $(date +%s) + 600)
    }
    EOF
    

    次の値を置き換えます。

    • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
    • PROJECT_ID: Google Cloud プロジェクト ID
    • AUDIENCES: サービス、ワークロード、またはアプリの想定オーディエンスを識別するわかりやすい文字列(例: "123456-my-app")。

JWT に署名する(REST API)

  1. jq ツールを使用して、JWT を文字列にエンコードし、curl リクエスト ペイロードを作成します。

    cat jwt_in.json | jq -Rsa >request.json
    
  2. リクエスト ペイロードを signJwt REST API メソッドに渡して、トークンに署名します。

    SA="serviceAccount:SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com"
    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/$SA:signJwt"
    

    次の値を置き換えます。

    • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
    • PROJECT_ID: Google Cloud プロジェクト ID

    返された signedJwt 値を signedJwt という環境変数に格納します。

JWT に署名する(gcloud CLI)

また、jwt_in.json ファイルを gcloud CLI の sign-jwt メソッドに直接渡すことで、JWT に署名することもできます。

gcloud iam service-accounts sign-jwt jwt_in.json jwt_out \
   --iam-account=SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com

次の値を置き換えます。

  • SERVICE_ACCOUNT_ID: サービス アカウントの ID。
  • PROJECT_ID: Google Cloud プロジェクト ID

署名付き JWT は jwt_out 出力ファイルに返されます。これを signedJwt という環境変数に格納します。

署名付き JWT をインデックス エンドポイントに送信する

Python

Vertex AI SDK for Python のインストールまたは更新の方法については、Vertex AI SDK for Python をインストールするをご覧ください。 詳細については、Python API リファレンス ドキュメントをご覧ください。

def vector_search_match_jwt(
    project: str,
    location: str,
    index_endpoint_name: str,
    deployed_index_id: str,
    queries: List[List[float]],
    num_neighbors: int,
    signed_jwt: str,
) -> List[List[aiplatform.matching_engine.matching_engine_index_endpoint.MatchNeighbor]]:
    """Query the vector search index.

    Args:
        project (str): Required. Project ID
        location (str): Required. The region name
        index_endpoint_name (str): Required. Index endpoint to run the query
        against. The endpoint must be a private endpoint.
        deployed_index_id (str): Required. The ID of the DeployedIndex to run
        the queries against.
        queries (List[List[float]]): Required. A list of queries. Each query is
        a list of floats, representing a single embedding.
        num_neighbors (int): Required. The number of neighbors to return.
        signed_jwt (str): Required. The signed JWT token for the private
        endpoint. The endpoint must be configured to accept tokens from JWT's
        issuer and encoded audience.

    Returns:
        List[List[aiplatform.matching_engine.matching_engine_index_endpoint.MatchNeighbor]] - A list of nearest neighbors for each query.
    """
    # Initialize the Vertex AI client
    aiplatform.init(project=project, location=location)

    # Create the index endpoint instance from an existing endpoint.
    my_index_endpoint = aiplatform.MatchingEngineIndexEndpoint(
        index_endpoint_name=index_endpoint_name
    )

    # Query the index endpoint for matches.
    resp = my_index_endpoint.match(
        deployed_index_id=deployed_index_id,
        queries=queries,
        num_neighbors=num_neighbors,
        signed_jwt=signed_jwt,
    )
    return resp

コマンドライン

同じ VPC ネットワーク内の Compute Engine VM から、次の例に示すように、MatchService gRPC エンドポイントを呼び出し、authorization ヘッダーで signedJwt トークンを渡します。

./grpc_cli call ${TARGET_IP}:10000 google.cloud.aiplatform.container.v1.MatchService.Match \
   '{deployed_index_id: "${DEPLOYED_INDEX_ID}", float_val: [-0.1,..]}' \
   --metadata "authorization: Bearer $signedJwt"

このコマンドを実行するには、次の環境変数を設定する必要があります。

  • TARGET_IP は、デプロイしたインデックス サーバーの IP アドレスです。この値を取得する方法については、インデックスをクエリして最近傍を取得するをご覧ください。
  • DEPLOYED_INDEX_ID: デプロイされたインデックスを一意に識別するユーザー指定の文字列。先頭は英字にします。英字、数字、アンダースコアのみ使用できます。形式のガイドラインについては、DeployedIndex.id をご覧ください。

signedJwt は、署名付き JWT を含む環境変数です。

トラブルシューティング

次の表に、一般的な gRPC エラー メッセージを示します。

gRPC エラー メッセージ 理由
インデックス「INDEX_ID」の Authorization ヘッダーが見つかりません gRPC メタデータに認証ヘッダーが含まれていません
JWT の形式が無効です トークンが不正な形式で、正しく解析できません
JWT 認証に失敗しました トークンの有効期限が切れているか、正しいサービス アカウントによって署名されていません
JWT 発行者が、許可された発行者のリストに含まれている必要があります トークン iss は、許可された発行元 auth_config にありません
インデックス「INDEX_ID」の権限チェックが失敗しました トークン aud または sub クレームが auth_config オーディエンスにありません。

次のステップ