Autenticación del token web JSON

Vector Search admite extremos de índice autenticados mediante tokens web JSON (JWT) autofirmados. Para controlar el acceso al extremo del índice, se configuró para aceptar solo JWT firmados emitidos por cuentas de servicio de Google autorizadas específicamente. Esto significa que solo los clientes que usan esas cuentas designadas pueden interactuar con el extremo.

En esta página, se describen los pasos necesarios para configurar un extremo de índice con autenticación de token web JSON (JWT) y ejecutar consultas en él.

Limitaciones

  • La autenticación de JWT solo es compatible con extremos privados con intercambio de tráfico de VPC o Private Service Connect (PSC).
  • La autenticación de JWT solo es compatible con las APIs de RPC del plano de datos (como MatchService) que se invocan mediante gRPC. En los ejemplos de RPC de esta página, se usa la herramienta de código abierto grpc_cli para enviar solicitudes de gRPC al servidor de índice implementado.
  • Las API de administrador para la creación, implementación y administración de índices están protegidas mediante roles predefinidos de IAM.

Crea y usa un JWT para consultar un índice

Sigue estos pasos para crear un extremo de índice y consultarlo con un JWT autofirmado.

Crea un índice

Crea un índice de Vector Search con las instrucciones en Crea un índice.

Crea un extremo privado

Sigue las instrucciones de una de las siguientes páginas de documentación para crear un extremo privado:

Crea una cuenta de servicio

Crea una cuenta de servicio y otórgale el rol de IAM de Creador de tokens de cuenta de servicio.

  1. Habilita la API de Service Account Credentials de IAM y crea una cuenta de servicio:

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

    Reemplaza los siguientes valores:

    • PROJECT_ID es el proyecto en el que se creará la cuenta de servicio.
    • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.

    Más información sobre cómo crear una cuenta de servicio.

  2. Usa uno de los siguientes comandos para otorgar el rol de IAM iam.serviceAccountTokenCreator a tu cuenta de servicio:

    • El siguiente comando te otorga permiso para crear JWT con la cuenta de servicio de una VM de Compute Engine que tenga la cuenta de servicio asociada:

      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"
      

      Reemplaza los siguientes valores:

      • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
      • PROJECT_ID es el proyecto en el que se creará la cuenta de servicio.
    • El siguiente comando otorga permiso para crear JWT con la cuenta de servicio de tu propia Cuenta de Google (en tu estación de trabajo):

      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
      

      Reemplaza los siguientes valores:

      • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
      • PROJECT_ID es el proyecto en el que se creará la cuenta de servicio.
      • EMAIL_ADDRESS: tu dirección de correo electrónico.

Implementa el índice en el extremo con la configuración de autenticación de JWT

  1. Implementa el índice en el extremo privado como se muestra en el siguiente ejemplo:

    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
    

    Reemplaza los siguientes valores:

    • INDEX_ENDPOINT_ID: Es el ID del extremo del índice.
    • INDEX_ID: Es el ID del índice.
    • DEPLOYED_INDEX_ID: Una cadena especificada por el usuario para identificar de forma inequívoca el índice implementado. Debe comenzar con una letra y contener solo letras, números o guiones bajos. Consulta DeployedIndex.id para obtener lineamientos de formato.
    • DEPLOYED_INDEX_NAME: Nombre visible del índice implementado.
    • AUDIENCES: Una cadena descriptiva que identifica el público esperado para tu servicio, carga de trabajo o app, por ejemplo, "123456-my-app".
    • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
    • PROJECT_ID: El ID del proyecto de Google Cloud.
    • LOCATION: la región en la que usas Vertex AI.

Consulta el índice con un JWT autofirmado

En un nivel alto, los pasos necesarios son los siguientes:

  1. Crea una carga útil de JWT.
  2. Firma el token con la cuenta de servicio que creaste antes.
  3. Consulta el índice mediante una llamada de gRPC y pasa el token en el encabezado de autorización.

Python

Crea y firma la carga útil de JWT

En este ejemplo, se usa el método sign_jwt de la biblioteca de credenciales de la API de IAM de Python para obtener un token firmado. Para obtener más información sobre cómo instalar y usar esta biblioteca, consulta la documentación de las bibliotecas cliente de la API de 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")

Línea de comandos

Crea la carga útil de JWT

La autenticación de búsqueda vectorial acepta JWTs firmados con una cuenta de servicio previamente autorizada para un público predefinido. El emisor debe especificar la cuenta de servicio y el público cuando se implementa un índice en un extremo privado. Una vez que se implementa un índice con esta configuración, todas las solicitudes a la API de gRPC para ese extremo deben incluir un encabezado de autorización que contenga un JWT firmado por la entidad emisora (una cuenta de servicio) y dirigido al público proporcionado. El JWT firmado se pasa como un token del portador en el encabezado authorization de la solicitud gRPC. Además de que la cuenta de servicio firme el JWT, este debe incluir los siguientes reclamos:

  • El reclamo iss (emisor permitido) debe ser la dirección de correo electrónico de la cuenta de servicio, por ejemplo:

    "iss": "SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com"
    
  • Las reclamaciones aud (público) y sub (sujeto) deben establecerse en el mismo valor. Esta es una cadena descriptiva que identifica el público esperado para tu servicio, carga de trabajo o app, por ejemplo:

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

    Este valor debe coincidir con el argumento --audiences que se pasó en el momento de la implementación del índice.

  • La reclamación iat (hora de emisión) debe configurarse en el momento en que se emite el token. La reclamación exp (hora de vencimiento) debe establecerse un poco más tarde (alrededor de una hora). Estos valores se expresan en tiempo Unix, por ejemplo:

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

En el siguiente ejemplo, se muestran estos reclamos en una sola carga útil de JWT:

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

La carga útil de JWT se firma con la cuenta de servicio especificada en la reclamación iss.

Crea el JWT

  1. Asegúrate de que tú (el emisor) puedas usar el rol roles/iam.serviceAccountTokenCreator en la cuenta de servicio.

  2. Crea un archivo JSON llamado jwt_in.json que contenga el JWT sin procesar:

    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
    

    Reemplaza los siguientes valores:

    • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
    • PROJECT_ID: El ID del proyecto de Google Cloud.
    • AUDIENCES: Una cadena descriptiva que identifica el público esperado para tu servicio, carga de trabajo o app, por ejemplo, "123456-my-app".

Firma el JWT (API de REST)

  1. Con la herramienta de jq, crea la carga útil de la solicitud curl mediante la codificación del JWT en una cadena:

    cat jwt_in.json | jq -Rsa >request.json
    
  2. Para firmar el token, pasa la carga útil de la solicitud al método signJwt de la API de 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"
    

    Reemplaza los siguientes valores:

    • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
    • PROJECT_ID: El ID del proyecto de Google Cloud.

    Almacena el valor de signedJwt que se muestra en una variable de entorno llamada signedJwt.

Firma el JWT (gcloud CLI)

Como alternativa, puedes firmar el JWT si pasas el archivo jwt_in.json directamente al método sign-jwt de gcloud CLI.

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

Reemplaza los siguientes valores:

  • SERVICE_ACCOUNT_ID: El ID para la cuenta de servicio.
  • PROJECT_ID: El ID del proyecto de Google Cloud.

El JWT firmado se muestra en el archivo de salida jwt_out. Guárdalo en una variable de entorno llamada signedJwt.

Envía el JWT firmado al extremo del índice

Python

Si deseas obtener información para instalar o actualizar el SDK de Vertex AI para Python, consulta Instala el SDK de Vertex AI para Python. Si deseas obtener más información, consulta la documentación de referencia de la API de 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

Línea de comandos

Desde una VM de Compute Engine en la misma red de VPC, llama al extremo MatchServicegRPC, pasándole el token signedJwt en el encabezado authorization, como se muestra en el siguiente ejemplo:

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

Para ejecutar este comando, deberás configurar las siguientes variables de entorno:

  • TARGET_IP es la dirección IP de tu servidor de índices implementado. Para obtener información sobre cómo recuperar este valor, ve a Consulta índices para obtener los vecinos más cercanos.
  • DEPLOYED_INDEX_ID: Una cadena especificada por el usuario para identificar de forma inequívoca el índice implementado. Debe comenzar con una letra y contener solo letras, números o guiones bajos. Consulta DeployedIndex.id para obtener lineamientos de formato.

signedJwt es la variable de entorno que contiene tu JWT firmado.

Soluciona problemas

En la siguiente tabla, se enumeran algunos mensajes de error comunes de gRPC.

Mensaje de error de gRPC Motivo
No se encontró el encabezado de autorización para el índice "INDEX_ID". Los metadatos de gRPC no contienen un encabezado de autorización.
El JWT tiene un formato no válido El token tiene un formato incorrecto y no se puede analizar correctamente
Error de autenticación de JWT El token caducó o no está firmado por la cuenta de servicio correcta.
El emisor de JWT debe estar en la lista de emisores permitidos. El token iss no se encuentra en las entidades emisoras permitidas de auth_config
No se pudo verificar el permiso del índice "INDEX_ID". El token aud o la reclamación sub no se encuentran en los públicos de auth_config

¿Qué sigue?