Authentification par jeton Web JSON

Vector Search accepte les points de terminaison d'index authentifiés à l'aide de jetons Web JSON (JWT) autosignés. Pour contrôler l'accès au point de terminaison de l'index, il est configuré pour n'accepter que les jetons JWT signés émis par des comptes de service Google spécifiquement autorisés. Cela signifie que seuls les clients utilisant ces comptes désignés peuvent interagir avec le point de terminaison.

Cette page décrit les étapes requises pour configurer un point de terminaison d'index avec l'authentification par jeton Web JSON (JWT) et exécuter des requêtes sur celui-ci.

Limites

  • L'authentification JWT n'est disponible que pour les points de terminaison privés avec appairage de VPC ou Private Service Connect (PSC).
  • L'authentification JWT n'est possible que pour les API RPC du plan de données (telles que MatchService) appelées à l'aide de gRPC. Les exemples RPC de cette page utilisent l'outil Open Source grpc_cli pour envoyer des requêtes gRPC au serveur d'index déployé.
  • Les API d'administration pour la création, le déploiement et la gestion d'index sont sécurisées à l'aide de rôles IAM prédéfinis.

Créer et utiliser un jeton JWT pour interroger un index

Suivez la procédure suivante pour créer un point de terminaison d'index et l'interroger avec un jeton JWT autosigné.

Créer un index

Créez un index Vector Search en suivant les instructions de la section Créer un index.

Créer un point de terminaison privé

Créez un point de terminaison privé en suivant les instructions de l'une des pages de documentation suivantes :

Créer un compte de service

Créez un compte de service et attribuez-lui le rôle IAM Créateur de jetons du compte de service.

  1. Activez l'API IAM Service Account Credentials, puis créez un compte de service :

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

    Remplacez les valeurs suivantes :

    • PROJECT_ID : projet dans lequel créer votre compte de service.
    • SERVICE_ACCOUNT_ID : ID du compte de service.

    Découvrez comment créer un compte de service.

  2. Exécutez l'une des commandes suivantes pour attribuer le rôle IAM iam.serviceAccountTokenCreator à votre compte de service :

    • La commande suivante vous autorise à créer des jetons JWT à l'aide du compte de service d'une VM Compute Engine à laquelle le compte de service est associé :

      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"
      

      Remplacez les valeurs suivantes :

      • SERVICE_ACCOUNT_ID : ID du compte de service.
      • PROJECT_ID : projet dans lequel créer votre compte de service.
    • La commande suivante permet de créer des jetons JWT à l'aide du compte de service de votre propre compte Google (sur votre poste de travail) :

      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
      

      Remplacez les valeurs suivantes :

      • SERVICE_ACCOUNT_ID : ID du compte de service.
      • PROJECT_ID : projet dans lequel créer votre compte de service.
      • EMAIL_ADDRESS : votre adresse e-mail.

Déployer l'index sur le point de terminaison avec la configuration d'authentification JWT

  1. Déployez l'index sur le point de terminaison privé comme indiqué dans l'exemple suivant :

    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
    

    Remplacez les valeurs suivantes :

    • INDEX_ENDPOINT_ID : ID du point de terminaison de l'index.
    • INDEX_ID : ID de l'index.
    • DEPLOYED_INDEX_ID : chaîne spécifiée par l'utilisateur pour identifier de manière unique l'index déployé. Ce nom doit commencer par une lettre et ne peut contenir que des lettres, des chiffres et des traits de soulignement. Consultez DeployedIndex.id pour connaître les consignes de format.
    • DEPLOYED_INDEX_NAME : nom à afficher de l'index déployé.
    • AUDIENCES : chaîne descriptive qui identifie l'audience attendue de votre service, charge de travail ou application (par exemple, "123456-my-app").
    • SERVICE_ACCOUNT_ID : ID du compte de service.
    • PROJECT_ID : ID de votre projet Google Cloud .
    • LOCATION : région dans laquelle vous utilisez Vertex AI.

Interroger l'index avec un jeton JWT autosigné

Dans les grandes lignes, la procédure à suivre est la suivante :

  1. Créez une charge utile JWT.
  2. Signez le jeton à l'aide du compte de service créé précédemment.
  3. Interrogez l'index en effectuant un appel gRPC, en transmettant le jeton dans l'en-tête d'autorisation.

Python

Créer et signer la charge utile JWT

Cet exemple utilise la méthode sign_jwt de la bibliothèque Identifiants des API Python IAM pour obtenir un jeton signé. Pour savoir comment installer et utiliser cette bibliothèque, consultez la documentation sur les bibliothèques clientes des API IAM.

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

Ligne de commande

Créer la charge utile JWT

L'authentification Vector Search accepte les jetons JWT signés avec un compte de service préautorisé, pour une audience prédéfinie. Le compte de service et l'audience doivent être spécifiés par l'appelant lorsqu'un index est déployé sur un point de terminaison privé. Une fois qu'un index est déployé avec ces paramètres, toutes les requêtes API gRPC adressées à ce point de terminaison doivent inclure un en-tête d'autorisation contenant un jeton JWT signé par l'émetteur (un compte de service) et destiné à l'audience indiquée. Le jeton JWT signé est transmis en tant que jeton de support dans l'en-tête authorization de la requête gRPC. En plus d'être signé par le compte de service, le jeton JWT doit inclure les revendications suivantes :

  • La revendication iss (émetteur autorisé) doit correspondre à l'adresse e-mail du compte de service. Par exemple :

    "iss": "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com"
    
  • Les revendications aud (audience) et sub (objet) doivent toutes deux être définies sur la même valeur. Il s'agit d'une chaîne descriptive qui identifie l'audience attendue de votre service, charge de travail ou application. Par exemple :

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

    Cette valeur doit correspondre à l'argument --audiences transmis au moment du déploiement de l'index.

  • La revendication iat (date/heure d'émission) doit être définie sur l'heure d'émission du jeton. La revendication exp (date/heure d'expiration) doit être définie sur une courte période ultérieure (environ une heure). Ces valeurs sont exprimées en epoch Unix. Par exemple :

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

L'exemple suivant illustre ces revendications dans une seule charge utile JWT :

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

La charge utile JWT est signée à l'aide du compte de service spécifié dans la revendication iss.

Créer le jeton JWT

  1. Assurez-vous que vous (l'appelant) pouvez utiliser le rôle roles/iam.serviceAccountTokenCreator sur le compte de service.

  2. Créez un fichier JSON nommé jwt_in.json contenant le jeton JWT brut :

    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
    

    Remplacez les valeurs suivantes :

    • SERVICE_ACCOUNT_ID : ID du compte de service.
    • PROJECT_ID : ID de votre projet Google Cloud .
    • AUDIENCES : chaîne descriptive qui identifie l'audience attendue de votre service, charge de travail ou application (par exemple, "123456-my-app").

Signer le jeton JWT (API REST)

  1. À l'aide de l'outil jq, créez la charge utile de la requête curl en encodant le jeton JWT dans une chaîne :

    cat jwt_in.json | jq -Rsa >request.json
    
  2. Signez le jeton en transmettant la charge utile de la requête à la méthode signJwt de l'API REST.

    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"
    

    Remplacez les valeurs suivantes :

    • SERVICE_ACCOUNT_ID : ID du compte de service.
    • PROJECT_ID : ID de votre projet Google Cloud .

    Stockez la valeur signedJwt renvoyée dans une variable d'environnement appelée signedJwt.

Signer le jeton JWT (gcloud CLI)

Vous pouvez également signer le jeton JWT en transmettant le fichier jwt_in.json directement à la méthode sign-jwt de la gcloud CLI.

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

Remplacez les valeurs suivantes :

  • SERVICE_ACCOUNT_ID : ID du compte de service.
  • PROJECT_ID : ID de votre projet Google Cloud .

Le jeton JWT signé est renvoyé dans le fichier de sortie jwt_out. Stockez-le dans une variable d'environnement appelée signedJwt.

Envoyer le jeton JWT signé au point de terminaison de l'index

Python

Pour savoir comment installer ou mettre à jour le SDK Vertex AI pour Python, consultez la section Installer le SDK Vertex AI pour Python. Pour en savoir plus, consultez la documentation de référence de l'API Python.

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

Ligne de commande

À partir d'une VM Compute Engine du même réseau VPC, appelez le point de terminaison MatchService gRPC en transmettant le jeton signedJwt dans l'en-tête authorization, comme illustré dans l'exemple suivant :

./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"

Pour exécuter cette commande, vous devez définir les variables d'environnement suivantes :

  • TARGET_IP est l'adresse IP du serveur d'index déployé. Pour savoir comment récupérer cette valeur, consultez Interroger les index pour obtenir les voisins les plus proches.
  • DEPLOYED_INDEX_ID : chaîne spécifiée par l'utilisateur pour identifier de manière unique l'index déployé. Ce nom doit commencer par une lettre et ne peut contenir que des lettres, des chiffres et des traits de soulignement. Consultez DeployedIndex.id pour connaître les consignes de format.

signedJwt est la variable d'environnement contenant votre jeton JWT signé.

Dépannage

Le tableau suivant liste certains messages d'erreur gRPC courants.

Message d'erreur gRPC Motif
En-tête d'autorisation introuvable pour l'index "INDEX_ID" Les métadonnées gRPC ne contiennent pas d'en-tête d'autorisation.
Le format du jeton JWT n'est pas valide. Le jeton est incorrect et ne peut pas être analysé correctement.
Échec de l'authentification JWT Le jeton a expiré ou n'est pas signé par le bon compte de service.
L'émetteur JWT doit figurer dans la liste des émetteurs autorisés. Le jeton iss ne figure pas dans les émetteurs autorisés auth_config.
Échec de la vérification des autorisations pour l'index "INDEX_ID" La revendication aud ou sub du jeton ne figure pas dans les audiences auth_config.

Étapes suivantes