Entrada de Agent Gateway a Agent Runtime con Model Armor

1. Introducción

En este codelab, se explora la administración de entrada de Agent Gateway para los agentes de IA alojados en Agent Runtime.

Agent Gateway, que opera en modo de entrada (cliente a agente), admite el control de las comunicaciones entre los clientes (usuarios finales humanos, agentes de escritorio, IDE de codificación, agentes pares, etcétera) y los agentes alojados en Agent Runtime. Este modo se usa para proteger a los agentes de ataques de inyección de instrucciones entrantes o contenido dañino enviado por los clientes. Todo el tráfico entrante se procesa con extensiones de autorización y Model Armor para proteger el punto de entrada de la red para todas las interacciones del agente.

Qué compilarás

  • Agent Gateway en modo de entrada (de cliente a agente)
  • Extensión de autorización de Model Armor
  • Agente de Agent Runtime ADK con identidad del agente
  • Datos de archivos de Cloud Storage consultados por el agente a través de MCP
  • Plantillas de Model Armor para analizar las instrucciones y respuestas de LLM
  • Plantillas de Sensitive Data Protection para desidentificar datos

figure1

Fig. 1: Arquitectura del codelab

Qué aprenderá

  • Cómo implementar Agent Gateway para filtrar el tráfico de entrada a un agente
  • Cómo configurar la delegación y las extensiones de autorización de Model Armor
  • Cómo crear e implementar plantillas personalizadas de Model Armor
  • Cómo crear e implementar plantillas personalizadas de Sensitive Data Protection
  • Cómo probar y validar las políticas de detección de LLM

Requisitos

  • Un proyecto de Google Cloud con la facturación habilitada.
  • Permisos de IAM para aprovisionar servicios de redes, conjuntos de datos de BigQuery y recursos de Agent Platform
  • Un shell compatible con POSIX (bash o zsh) con Google Cloud CLI (componente gcloud) instalado
  • Herramientas de línea de comandos: git, curl, jq (procesador JSON), Python 3 y uv (administrador de paquetes de Python)

2. Conceptos

Dirección del tráfico y roles de puerta de enlace

Agent Gateway funciona como un proxy de red compatible con agentes, pero su rol operativo cambia según la dirección del tráfico:

  • Modo de agente a cualquier lugar (salida): Funciona como un proxy de salida. Cuando un agente llama a herramientas de bases de datos externas, servidores de MCP de terceros o APIs, la puerta de enlace de salida administra el descubrimiento de servicios, el enrutamiento, el protocolo TLS mutuo (mTLS), la inserción dinámica de credenciales de OAuth y el control de acceso a los extremos.
  • Modo de cliente a agente (entrada): Funciona como una puerta de enlace de seguridad de frontend. Su objetivo principal es proteger la entrada al tiempo de ejecución del agente interceptando y limpiando las instrucciones entrantes en lenguaje natural antes de que lleguen al código del agente o a los modelos de IA.

Ruta de acceso de entrada a Agent Runtime

Las solicitudes del cliente dirigidas a un agente alojado en Agent Runtime se destinan al endpoint de API de aiplatform.googleapis.com.

POST https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}:query

Este flujo de comunicación entrante al endpoint de API representa la ruta de entrada de cliente a agente.

Para proteger esta ruta de entrada administrada por Google, Agent Gateway se integra directamente con el Google Front End (GFE) en la capa de infraestructura de entrega de la API. Cuando se implementa un agente administrado en Agent Runtime, Google vincula de forma nativa la política de autorización de la puerta de enlace de entrada a las solicitudes entrantes del cliente en el perímetro de la red.

figure2

Fig. 2: Gobernanza de entrada con Agent Gateway a Agent Runtime

Dado que la inspección se realiza en el nivel de frontend antes de que las solicitudes ingresen en el entorno de ejecución del agente, esta arquitectura no introduce ninguna sobrecarga de red adicional ni latencia de salto interna. La infraestructura de frontend controla el ajuste de escala de forma automática, lo que elimina la necesidad de administrar rangos de IP internos, balanceadores de cargas o rutas de DNS personalizadas.

Limpieza intercalada de amenazas con Model Armor

La evaluación de las credenciales del llamador y la aplicación del control de acceso de IAM (roles/aiplatform.user) se controlan de forma nativa en el nivel de hosting de la API de aiplatform. La puerta de enlace de entrada en sí no realiza la autorización de identidad, sino que se enfoca en la seguridad del contenido con extensiones de autorización configuradas con un perfil de CONTENT_AUTHZ. La puerta de enlace actúa como un punto de aplicación de políticas intercalado, ya que intercepta las instrucciones en lenguaje natural en tránsito antes de que lleguen al bucle de razonamiento del agente de IA o al LLM subyacente.

Cuando un mensaje entrante del usuario llega al servicio de frontend, la puerta de enlace inicia una llamada ext_proc (procesamiento externo) al servicio de extensión de autorización regional de Model Armor, que transmite la llamada al plano de datos de Model Armor. Model Armor actúa como un firewall de lenguaje natural, ya que evalúa el texto en función de plantillas activas para detectar riesgos de seguridad:

  • Intentos de inyección de instrucciones indirecta y jailbreak
  • URLs maliciosas, lenguaje tóxico o contenido inseguro
  • Filtración de datos sensibles y de información de identificación personal (PII)

Si la plantilla incluye filtros de Sensitive Data Protection (SDP), Model Armor realiza una llamada gRPC adicional al servicio de Cloud SDP. Cloud SDP inspecciona la carga útil con la plantilla especificada, realiza cualquier desidentificación o ocultamiento solicitado y devuelve el resultado saneado a la cadena para que se reenvíe de forma segura.

Si se detecta un incumplimiento de política o una coincidencia de datos sensibles sin ocultar, la puerta de enlace bloquea o oculta la carga útil en el borde antes de ingresar al tiempo de ejecución. Como resultado, la aplicación del agente de IA en ejecución permanece protegida y nunca procesa cargas útiles maliciosas o sin editar.

Aquí concluye la sección de conceptos. A continuación, se encuentra la sección de Configuración.

3. Configuración

Roles de IAM obligatorios

Se requieren los siguientes roles para crear los recursos en este codelab:

Categoría

Rol de IAM requerido (ID)

Descripción

Administración de API

roles/serviceusage.serviceUsageAdmin

Habilita los servicios de la API de Google Cloud

Redes y puerta de enlace

roles/networkservices.admin

Aprovisiona Agent Gateway

Service Extensions

roles/serviceextensions.admin

Configura las extensiones de enrutamiento

Seguridad de red

roles/networksecurity.admin

Implementa políticas de autorización

Protección de datos sensibles

roles/dlp.admin

Administra las plantillas de inspección y desidentificación de SDP

Model Armor

roles/modelarmor.admin

Crea y administra plantillas de seguridad

Agent Platform

roles/aiplatform.admin

Implementa cargas de trabajo de Agent Runtime

Cloud Storage

roles/storage.admin

Administra los buckets de datos de clientes y de implementación

Administración de IAM

roles/resourcemanager.projectIamAdmin

Vincula permisos a nivel del proyecto para la identidad del agente

Registros y auditoría

roles/logging.viewer

Cómo inspeccionar registros y registros de auditoría

Como alternativa, usa un rol básico amplio, como roles/admin, o un rol heredado, como roles/owner.

Accede a tu proyecto

En este codelab, se usa un solo proyecto de Google Cloud. En los pasos de configuración, se usan la CLI de gcloud y los comandos de shell de Linux.

Para comenzar, accede a la línea de comandos de tu proyecto de Google Cloud:

Establece tu ID del proyecto

gcloud config set project SET_YOUR_PROJECT_ID_HERE

Autentica la sesión

# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login

Establece variables de entorno de shell

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"
echo ${SLUG}
echo ${REGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)
echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-cta"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export RE_AGENT_NAME="agent-crm"
export RE_AGENT_ID_SET="principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJ_NO}"
export STAGING_BUCKET="agent-staging-${PROJ_NO}"
export DATA_BUCKET="customer-data-${PROJ_NO}"
export MCP_URL="https://storage.mtls.googleapis.com/storage/mcp"
echo ${AGW_NAME}
echo ${AGW_URI}
echo ${RE_AGENT_NAME}
echo ${RE_AGENT_ID_SET}
echo ${STAGING_BUCKET}
echo ${DATA_BUCKET}
echo ${MCP_URL}
# create local dir for config files
mkdir -p cfg

Si ejecutas una instalación autoadministrada del SDK de Google Cloud (es decir, fuera de Cloud Shell), actualiza los componentes a la versión más reciente.

# update gcloud cli
gcloud components update

Habilita los servicios de la API

# enable google apis (agent platform bundle, part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iamconnectors.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (agent platform bundle, part 2)
gcloud services enable \
  securitycenter.googleapis.com \
  saasservicemgmt.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com
# enable google apis (all the rest)
gcloud services enable \
  dlp.googleapis.com

Aquí concluye la parte de configuración… a continuación, se abordará la sección Puerta de enlace.

4. Puerta de enlace

Implementa un Agent Gateway administrado por Google que opere en modo cliente a agente (CLIENT_TO_AGENT). A diferencia de las puertas de enlace de salida que requieren asociaciones del Registro de agentes para enrutar las llamadas salientes, la puerta de enlace de entrada se vincula directamente en el nivel de frontend para servir como punto de aplicación intercalado para las instrucciones entrantes dirigidas a Agent Runtime.

Si bien las políticas de salida suelen comenzar en modo DRY_RUN en la capa de puerta de enlace, la administración de contenido de entrada (CONTENT_AUTHZ) se implementa directamente en modo de aplicación forzosa. En cambio, el registro de solo auditoría o el bloqueo activo detallados se controlan de forma ascendente dentro de las plantillas individuales de Model Armor.

Crear puerta de enlace

# create agent gateway config file
cat > cfg/${AGW_NAME}.yaml <<EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: CLIENT_TO_AGENT
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}.yaml" \
  --location=${REGION}

Verifica la puerta de enlace

# list agent gateways (in region)
gcloud network-services agent-gateways list --location=${REGION}
# show agent gateway details (verify deployment state)
gcloud network-services agent-gateways describe ${AGW_NAME} --location=${REGION}

Aquí concluye la sección de la puerta de enlace. A continuación, veremos la sección de Model Armor.

5. Model Armor

Plantillas de SDP

Crea una plantilla de inspección y desidentificación de Sensitive Data Protection (SDP) para usarla en la plantilla de respuesta de Model Armor. Esta configuración marca los números de seguridad social de EE.UU. (NSS) para su ocultamiento.

Crea una plantilla de inspección

La plantilla de inspección identifica la información sensible (US_SOCIAL_SECURITY_NUMBER) en los datos.

# create inspect template
curl -fsS -X POST "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/inspectTemplates" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "x-goog-user-project: ${PROJ_ID}" \
  -d @- << EOF
{
  "templateId": "agw-ssn-inspect-template",
  "inspectTemplate": {
    "displayName": "ssn inspect template",
    "inspectConfig": {
      "infoTypes": [
        { "name": "US_SOCIAL_SECURITY_NUMBER" }
      ],
      "minLikelihood": "POSSIBLE"
    }
  }
}
EOF

Crea una plantilla de desidentificación

La plantilla de desidentificación especifica la transformación que se aplicará a los números de seguridad social que encuentre la plantilla de inspección. En este caso, la transformación consiste en reemplazar el NSS por el infotipo.

# create de-identify template
curl -fsS -X POST "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/deidentifyTemplates" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "x-goog-user-project: ${PROJ_ID}" \
  -d @- << EOF
{
  "templateId": "agw-ssn-redaction-template",
  "deidentifyTemplate": {
    "displayName": "SSN Redaction Template",
    "deidentifyConfig": {
      "infoTypeTransformations": {
        "transformations": [{
          "primitiveTransformation": { "replaceWithInfoTypeConfig": {} }
        }]
      }
    }
  }
}
EOF

Verifica las plantillas de SDP

# get (describe) inspect template
curl -fsS -X GET "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/inspectTemplates" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "x-goog-user-project: ${PROJ_ID}" | jq
# get (describe) de-identify template
curl -fsS -X GET "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/deidentifyTemplates" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "x-goog-user-project: ${PROJ_ID}" | jq

Plantillas de Model Armor

El endpoint predeterminado de la API de Model Armor es global (modelarmor.googleapis.com). Sin embargo, los recursos de Model Armor para plantillas y motores de evaluación se localizan en regiones geográficas específicas. El proxy de extremo regional (REP) de Google Cloud, o extremo de API regional, para Model Armor es https://modelarmor.${LOCATION}.rep.googleapis.com/.

De forma predeterminada, cuando se ejecuta gcloud model-armor ..., la CLI intenta enviar solicitudes a la API al extremo global estándar (https://modelarmor.googleapis.com/). Se usa una anulación del extremo de la API para redireccionar todas las solicitudes HTTP del SDK o la CLI de Model Armor directamente al nivel de la API regional rep.googleapis.com en el que se crean, almacenan y consultan esos modelos vinculados a la ubicación.

Cómo establecer la anulación de la API

# set api endpoint override per location
gcloud config set api_endpoint_overrides/modelarmor "https://modelarmor.${REGION}.rep.googleapis.com/"

Verifica la anulación de la API

# view api overrides on active gcloud config
gcloud config list api_endpoint_overrides/

Crea una plantilla de filtro de solicitudes

Crea una plantilla de filtro de solicitudes para bloquear la incitación al odio o a la violencia, el hostigamiento, el contenido sexual explícito y los ataques de inyección de URI. Se habilitará el registro para capturar información detallada sobre los eventos relacionados con la aplicación de políticas. También se configuran códigos y mensajes de error personalizados para cuando se bloquea una solicitud.

# create model armor template (request)
gcloud beta model-armor templates create ${AGW_NAME}-modar-req-template \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --rai-settings-filters='[
    { "filterType": "HATE_SPEECH", "confidenceLevel": "MEDIUM_AND_ABOVE" },
    { "filterType": "HARASSMENT", "confidenceLevel": "MEDIUM_AND_ABOVE" },
    { "filterType": "SEXUALLY_EXPLICIT", "confidenceLevel": "MEDIUM_AND_ABOVE" }
  ]' \
  --pi-and-jailbreak-filter-settings-enforcement=enabled \
  --pi-and-jailbreak-filter-settings-confidence-level=medium-and-above \
  --template-metadata-enforcement-type=INSPECT_AND_BLOCK \
  --malicious-uri-filter-settings-enforcement=enabled \
  --template-metadata-custom-llm-response-safety-error-code=798 \
  --template-metadata-custom-llm-response-safety-error-message="ahoy! model response blocked by content filter :(" \
  --template-metadata-custom-prompt-safety-error-code=799 \
  --template-metadata-custom-prompt-safety-error-message="ahoy! the request was blocked by ye content filter... so rephrase the prompt and try again!" \
  --template-metadata-ignore-partial-invocation-failures \
  --template-metadata-log-operations \
  --template-metadata-log-sanitize-operations

Crea una plantilla de filtro de respuestas

Crea una plantilla de filtro de respuesta para bloquear el mismo contenido que la plantilla de filtro de solicitud. DLP está configurado en la etapa de respuesta para anonimizar los números de seguridad social de los mensajes que regresan al cliente desde el agente.

# create model armor template (response)
gcloud beta model-armor templates create ${AGW_NAME}-modar-resp-template \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --rai-settings-filters='[
      { "filterType": "HATE_SPEECH", "confidenceLevel": "MEDIUM_AND_ABOVE" },
      { "filterType": "HARASSMENT", "confidenceLevel": "MEDIUM_AND_ABOVE" },
      { "filterType": "SEXUALLY_EXPLICIT", "confidenceLevel": "MEDIUM_AND_ABOVE" }
  ]' \
  --malicious-uri-filter-settings-enforcement=enabled \
  --advanced-config-inspect-template=projects/${PROJ_ID}/locations/${REGION}/inspectTemplates/agw-ssn-inspect-template \
  --advanced-config-deidentify-template=projects/${PROJ_ID}/locations/${REGION}/deidentifyTemplates/agw-ssn-redaction-template \
  --template-metadata-enforcement-type=INSPECT_AND_BLOCK \
  --template-metadata-custom-llm-response-safety-error-code=798 \
  --template-metadata-custom-llm-response-safety-error-message="ahoy! model response blocked by content filter :(" \
  --template-metadata-custom-prompt-safety-error-code=799 \
  --template-metadata-custom-prompt-safety-error-message="ahoy! the request was blocked by ye content filter... so rephrase the prompt and try again!" \
  --template-metadata-ignore-partial-invocation-failures \
  --template-metadata-log-operations \
  --template-metadata-log-sanitize-operations

Verifica plantillas de Model Armor

# list model armor templates
gcloud model-armor templates list --location=${REGION}
# show request filter template details
gcloud model-armor templates describe ${AGW_NAME}-modar-req-template --location=${REGION}
# show response filter template details
gcloud model-armor templates describe ${AGW_NAME}-modar-resp-template --location=${REGION}

Permisos de IAM

Model Armor realiza llamadas a la API para invocar el servicio de Sensitive Data Protection (SDP). Otorga permisos de IAM a la identidad del servicio de Model Armor para usar las plantillas de inspección y desidentificación de SDP.

Vincula la política de IAM para Sensitive Data Protection

# grant dlp (sdp) user role to the model armor service identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-modelarmor.iam.gserviceaccount.com" \
  --role="roles/dlp.user"

Verifica los permisos de IAM

# show iam policy for all dlp (sdp) roles on project
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.role:roles/dlp" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

Aquí concluye la sección de Model Armor. A continuación, veremos la sección de Autorización.

6. Autorización

Permisos de IAM

Para inspeccionar el tráfico intercalado con Model Armor, el agente de servicio de Service Extensions (DEP) requiere vinculaciones de IAM explícitas (incluso entre recursos dentro del mismo proyecto):

  • roles/modelarmor.calloutUser y roles/serviceusage.serviceUsageConsumer: Se otorgan en el proyecto de la puerta de enlace para permitir los textos destacados de inspección intercalados.
  • roles/modelarmor.user: Se otorga en el proyecto de plantilla para permitir el acceso y la evaluación de las plantillas de Model Armor.

Vincula la política de IAM para Model Armor

# grant model armor callout user role to dep (service extension) service agent
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/modelarmor.calloutUser"

# grant service usage consumer role to dep (service extension) service agent
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/serviceusage.serviceUsageConsumer"

# grant model armor user role to dep (service extension) service agent
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/modelarmor.user"

Verifica los permisos de IAM

# show iam policy on project for dep (service extension) service agent
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --format="table(bindings.members:label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

Extensión de autorización

La configuración de la extensión de autorización para Agent Gateway define los parámetros de configuración de integración que se aplicarán al tráfico de cargas útiles entrantes y salientes. La configuración define el servicio de procesamiento externo (service) que hace referencia a la API regional de Model Armor y se vincula a las plantillas de solicitud y respuesta específicas con el campo de metadatos model_armor_settings.

Crea una extensión de autorización

# create authz extension config file (enforced mode)
cat > cfg/${AGW_NAME}-svc-ext-authz-modar.yaml <<EOF
name: ${AGW_NAME}-svc-ext-authz-modar
service: modelarmor.${REGION}.rep.googleapis.com
metadata:
  model_armor_settings: '[
    {
      "request_template_id": "projects/${PROJ_ID}/locations/${REGION}/templates/${AGW_NAME}-modar-req-template",
      "response_template_id": "projects/${PROJ_ID}/locations/${REGION}/templates/${AGW_NAME}-modar-resp-template"
    }
  ]'
failOpen: true
timeout: 5s
EOF

Importa la extensión de autorización

# import authz extension file
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-modar \
  --source=cfg/${AGW_NAME}-svc-ext-authz-modar.yaml \
  --location=${REGION}

Verifica la extensión de autorización

# list authz extensions
gcloud service-extensions authz-extensions list --location=${REGION}
# show authz extension details
gcloud service-extensions authz-extensions describe ${AGW_NAME}-svc-ext-authz-modar \
  --location=${REGION}

Política de autorización

Las políticas de autorización usan perfiles de políticas para determinar el tipo de evaluación que se realiza. Si bien los perfiles basados en solicitudes (REQUEST_AUTHZ) evalúan los encabezados HTTP, esta configuración usa un perfil de autorización basado en el contenido (CONTENT_AUTHZ) para vincular la extensión de Model Armor a la puerta de enlace para una inspección profunda de la carga útil.

Crea una política de autorización

# create authz policy config file (attach dry-run authz extension)
cat > cfg/${AGW_NAME}-authz-policy-modar.yaml <<EOF
name: ${AGW_NAME}-authz-policy-modar
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: CONTENT_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-modar"
EOF

Importa la política de autorización

# import authz policy config file (enable authz policy)
gcloud beta network-security authz-policies import ${AGW_NAME}-authz-policy-modar \
  --source=cfg/${AGW_NAME}-authz-policy-modar.yaml \
  --location=${REGION}

Verifica la política de autorización

# list authz policies
gcloud beta network-security authz-policies list --location=${REGION}
# show authz policy details
gcloud beta network-security authz-policies describe ${AGW_NAME}-authz-policy-modar \
  --location=${REGION}

Con esto, concluye la parte de autorización… a continuación, veremos la sección Codebase.

7. Base de código

El código del agente y los datos de archivo que se usan para este codelab se mantienen en un repositorio remoto de GitHub de Google Cloud. En los siguientes pasos, se clonará el repositorio de forma local, se copiarán los archivos necesarios en la estructura del directorio de trabajo actual y, luego, se borrarán los archivos temporales.

Recupera artefactos remotos

# clone remote repository to temp local dir
git clone https://github.com/GoogleCloudPlatform/cloud-networking-solutions.git ./temp_agw_cuj_arun_ingress_modar
# copy agent runtime and endpoint definitions to working project dir
cp -r temp_agw_cuj_arun_ingress_modar/codelabs/agw-cuj-arun-ingress-modar/agent-crm ./agent-crm
# remove temporary directory
rm -rf temp_agw_cuj_arun_ingress_modar

Agent Runtime usa un bucket de almacenamiento para la etapa de pruebas para subir, compilar e implementar el código de la aplicación del agente empaquetado y sus artefactos de dependencia.

Crea un bucket de almacenamiento para la etapa de pruebas

# create storage bucket
gcloud storage buckets create gs://${STAGING_BUCKET} --location=${REGION}

Verifica el bucket de almacenamiento

# list storage buckets
gcloud storage buckets list --format="value(storage_url)"

Aquí concluye la sección sobre la base de código. A continuación, se abordará la sección Datos del cliente de GCS.

Datos del cliente

Crea un bucket de Cloud Storage para almacenar datos del cliente. El agente leerá directamente con la biblioteca cliente estándar de Google Cloud que llama al extremo del MCP de Cloud Storage.

Crea un bucket de almacenamiento para los datos del cliente

# create storage bucket
gcloud storage buckets create gs://${DATA_BUCKET} --location=${REGION}

Verifica el bucket de almacenamiento

# list storage buckets
gcloud storage buckets list --format="value(storage_url)"

Subir datos de clientes

# copy local data to bucket
gcloud storage cp -r ./agent-crm/data/* gs://${DATA_BUCKET}/

Verifica los datos del cliente

# list bucket objects
gcloud storage ls gs://${DATA_BUCKET}/ --long

Aquí concluye la sección sobre los datos del cliente de GCS. A continuación, se abordará la sección del agente de ADK.

8. Agente de ADK

El agente del ADK de agent-crm implementado en Agent Runtime se configura con los siguientes parámetros en la secuencia de comandos de implementación para integrarse con Agent Platform:

  • "identity_type": types.IdentityType.AGENT_IDENTITY para aprovisionar una identidad principal única basada en SPIFFE para el agente
  • "client_to_agent_config": {"agent_gateway": "${AGW_URI}"} para dirigir todo el tráfico entrante del agente a la ruta de aplicación y evaluación de políticas de Agent Gateway

También se le pasa al agente la URL del servidor MCP de mTLS para el servidor MCP de Cloud Storage y el nombre del bucket de datos para invocar la herramienta de MCP de GCS a través de una conexión segura.

Implementa el agente

# deploy agent
uv --directory agent-crm run python3 deploy_agent.py \
  --project=${PROJ_ID} \
  --region=${REGION} \
  --src-dir=./agent \
  --staging-bucket=${STAGING_BUCKET} \
  --display-name="${RE_AGENT_NAME}" \
  --description="agent for customer data" \
  --mcp-server-url="${MCP_URL}" \
  --data-bucket=${DATA_BUCKET} \
  --enable-telemetry \
  --enable-agent-identity \
  --agent-gateway-ingress=${AGW_URI} \
  --allow-token-sharing

Verifica la implementación

Recupera los signos vitales de la implementación

# fetch agent runtime (reasoning engine) resource id
export RE_ENGINE_ID=$(curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  | jq -r --arg name "${RE_AGENT_NAME}" '.reasoningEngines[] | select(.displayName==$name) | .name | split("/") | last')
echo ${RE_ENGINE_ID}
# fetch agent runtime (reasoning engine) agent identity
export RE_AGENT_IDENTITY=$(gcloud agent-registry agents list \
  --project=${PROJ_ID} --location=${REGION} --filter="displayName=${RE_AGENT_NAME}" \
  --format="value(attributes.'agentregistry.googleapis.com/system/RuntimeIdentity'.principal)")
echo ${RE_AGENT_IDENTITY}

Verifica la configuración de la puerta de enlace

# show agent runtime config details (gateway config)
curl -s -X GET "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  | jq '{displayName: .displayName, name: .name, effectiveIdentity: .spec.effectiveIdentity, agentGatewayConfig: .spec.deploymentSpec.agentGatewayConfig}'

Permisos de IAM

Vincula políticas de IAM para la identidad del agente

# grant mcp tool user role to agent set (all agent runtime agents in project)
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_ID_SET}" \
  --role="roles/mcp.toolUser"
# grant storage object viewer role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/storage.objectViewer"

# grant aiplatform user role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/aiplatform.user"

# grant cloudtrace agent role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/cloudtrace.agent"

# grant cloud monitoring metric writer role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/monitoring.metricWriter"
# grant cloud logging log writer role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/logging.logWriter"

# grant telemetry writer role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/telemetry.writer"

# grant service usage consumer role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/serviceusage.serviceUsageConsumer"

# grant browser role to agent identity
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="${RE_AGENT_IDENTITY}" \
  --role="roles/browser"

Verifica los permisos de IAM

# show agent identity roles on project
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${RE_AGENT_IDENTITY}" \
  --format="table(bindings.members.sub('^.*locations/', 'principal://agents.[...]/locations/'):label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"
# show agent set roles on project
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${RE_AGENT_ID_SET}" \
  --format="table(bindings.members.sub('^.*platformContainer/', 'principalSet://agents.[...]/'):label=PRINCIPAL_IDENTITY, bindings.role:label=ROLE)"

Aquí concluye la sección del agente del ADK… a continuación, se muestra la sección Prueba.

9. Prueba

Envía consultas desde la CLI

Prueba una instrucción segura

# post query to agent streamQuery
curl --no-buffer -s -X POST "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}:streamQuery" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "X-Goog-User-Project: ${PROJ_ID}" \
  -d @- <<EOF | jq -r --unbuffered 'if type == "array" then .[] else . end | select(.content.parts != null) | .content.parts[].text // empty'
{
  "input": {
    "message": "what are the names of our west customers?",
    "user_id": "test-user"
  }
}
EOF

Deberías ver una respuesta como la siguiente… "Nuestros clientes del oeste son Bob Johnson y Alice Brown".

Prueba un activador de ocultamiento

# post query to agent streamQuery
curl --no-buffer -s -X POST "https://${REGION}-aiplatform.googleapis.com/v1beta1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}:streamQuery" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "X-Goog-User-Project: ${PROJ_ID}" \
  -d @- <<EOF | jq -r --unbuffered 'if type == "array" then .[] else . end | select(.content.parts != null) | .content.parts[].text // empty'
{
  "input": {
    "message": "what are ssn's for bob johnson and alice brown?",
    "user_id": "test-user"
  }
}
EOF

Probar otra instrucción segura

# post query to agent streamQuery
curl --no-buffer -s -X POST "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}:streamQuery" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" -H "X-Goog-User-Project: ${PROJ_ID}" \
  -d @- <<EOF | jq -r --unbuffered 'if type == "array" then .[] else . end | select(.content.parts != null) | .content.parts[].text // empty'
{
  "input": {
    "message": "what are bob johnson's and alice brown's email addresses?",
    "user_id": "test-user"
  }
}
EOF

Registros de auditoría

Visualiza los registros de seguimiento

Cuando la telemetría está habilitada, Agent Runtime transmite eventos estructurados que representan las búsquedas de los usuarios, los parámetros de las herramientas, los flujos de ejecución y los resultados de la elección del modelo.

# show agent runtime (reasoning engine) telemetry and trace logs
gcloud logging read \
  "logName:\"projects/${PROJ_ID}/logs/aiplatform.googleapis.com%2Freasoning_engine_stdout\" AND labels.managed-by=\"reasoning-engine\"" \
  --project=${PROJ_ID} \
  --limit=15 \
  --format="table(
    timestamp.date(format=\"%I:%M:%S %p\", tz=LOCAL):label=TIME,
    trace.basename().sub('^(.{8}).*$', '\\1'):label=TRACE_ID,
    labels.\"event.name\".scope(-1):label=EVENT,
    jsonPayload.content.role:label=ROLE,
    jsonPayload.content.parts[0].text:label=TEXT_CONTENT,
    jsonPayload.content.parts[0].function_call.name:label=TOOL_CALL
  )"

TRACE_ID agrupa la búsqueda del usuario, las llamadas a herramientas intermedias y las decisiones del modelo en una sola línea de tiempo:

TIME         TRACE_ID  EVENT                  ROLE   TEXT_CONTENT                                     TOOL_CALL
HH:MM:SS PM  3070a1fd  gen_ai.choice          model  Bob Johnson's SSN is 219-45-7895.
                                                     Alice Brown's SSN is 219-45-7896.
HH:MM:SS PM  3070a1fd  gen_ai.user.message    user
HH:MM:SS PM  3070a1fd  gen_ai.user.message    model                                                   read_customer_file
HH:MM:SS PM  3070a1fd  gen_ai.user.message    user
HH:MM:SS PM  3070a1fd  gen_ai.user.message    model                                                   read_customer_file
HH:MM:SS PM  3070a1fd  gen_ai.user.message    user
HH:MM:SS PM  3070a1fd  gen_ai.user.message    model                                                   list_customer_files
HH:MM:SS PM  3070a1fd  gen_ai.user.message    user   what are ssn's for bob johnson and alice brown?
HH:MM:SS PM  3070a1fd  gen_ai.system.message
HH:MM:SS PM  3070a1fd  gen_ai.choice          model                                                   read_customer_file

Consulta los registros de limpieza de Model Armor

Estos registros muestran la amenaza bidireccional intercalada en tiempo real y el saneamiento que realiza Model Armor a medida que el tráfico fluye a través de Agent Gateway.

# show model armor logs
gcloud logging read \
  "logName:\"projects/${PROJ_ID}/logs/modelarmor.googleapis.com%2Fsanitize_operations\"" \
  --project=${PROJ_ID} \
  --limit=50 \
  --format="table(
    timestamp.date(format=\"%I:%M:%S %p\", tz=LOCAL):label=TIME,
    jsonPayload.sanitizationResult.sanitizationVerdict:label=VERDICT,
    jsonPayload.sanitizationInput.byteItem.byteData.decode(base64).decode(utf-8).sub('\n', ' \\\\\\\\n ').trailoff(123):label=INPUT_DATA
  )"

Observa la entrada de registro de la solicitud bloqueada y saneada.

TIME         VERDICT                                 INPUT_DATA
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_ALLOW  Bob Johnson's email address is bob.j@example.com. \n Alice Brown's email address is alice.b...
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_ALLOW  what are bob johnson's and alice brown's email addresses?
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_BLOCK  6��
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_ALLOW  what are ssn's for bob johnson and alice brown?
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_ALLOW  Our west customers are: Bob Johnson and Alice Brown.
HH:MM:SS PM  MODEL_ARMOR_SANITIZATION_VERDICT_ALLOW  what are the names of our west customers?

Aquí concluye la sección de prueba. A continuación, se encuentra la sección de limpieza.

10. Limpieza

# remove agent iam bindings
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/storage.objectViewer"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/aiplatform.user"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/cloudtrace.agent"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/monitoring.metricWriter"

# next
# remove more agent and agent set iam bindings
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/logging.logWriter"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/telemetry.writer"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/serviceusage.serviceUsageConsumer"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_IDENTITY}" --role="roles/browser"

# next
# remove rest of iam bindings
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="${RE_AGENT_ID_SET}" --role="roles/mcp.toolUser"
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} --member="serviceAccount:service-${PROJ_NO}@gcp-sa-modelarmor.iam.gserviceaccount.com" --role="roles/dlp.user"

# next
# delete agent runtime (reasoning engine) agent
curl -s -X DELETE "https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJ_ID}/locations/${REGION}/reasoningEngines/${RE_ENGINE_ID}?force=true" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json"

# next
# delete storage
gcloud -q storage rm --recursive gs://${STAGING_BUCKET}
gcloud -q storage rm --recursive gs://${DATA_BUCKET}

# next
# delete authz resources
gcloud -q beta network-security authz-policies delete ${AGW_NAME}-authz-policy-modar --location=${REGION}

gcloud -q beta service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-modar --location=${REGION} --async

# next
# remove dep (service extensions) service agent iam bindings
gcloud -q projects remove-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/modelarmor.calloutUser"

gcloud -q projects remove-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/serviceusage.serviceUsageConsumer"

gcloud -q projects remove-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-dep.iam.gserviceaccount.com" \
  --role="roles/modelarmor.user"

# next
# delete model armor templates
gcloud -q model-armor templates delete ${AGW_NAME}-modar-resp-template --location=${REGION}
gcloud -q model-armor templates delete ${AGW_NAME}-modar-req-template --location=${REGION}

# unset model armor api endpoint override
gcloud config unset api_endpoint_overrides/modelarmor

# next
# delete sdp (dlp) templates
curl -fsS -X DELETE "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/deidentifyTemplates/agw-ssn-redaction-template" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "x-goog-user-project: ${PROJ_ID}"

curl -fsS -X DELETE "https://dlp.googleapis.com/v2/projects/${PROJ_ID}/locations/${REGION}/inspectTemplates/agw-ssn-inspect-template" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "x-goog-user-project: ${PROJ_ID}"

# next
# delete agent gateway ingress
gcloud -q network-services agent-gateways delete ${AGW_NAME} --location=${REGION} --async

# end

Aquí concluye la sección de limpieza. A continuación, se encuentra la sección de Conclusión.

11. Conclusión

¡Felicitaciones! Implementaste correctamente Agent Gateway y controlaste el tráfico entrante a un agente de IA.

cosmopup

Cosmopup cree que los codelabs son geniales.

¿Qué sigue?

Si tienes comentarios, preguntas o correcciones, usa este formulario de comentarios.

¡Gracias!