跳到正文
DEV Community· Franchesco Romero·· 3 小時前AI 評分71

如何以身份視角審核 AI 智能體的實際存取範圍

Auditar agentes como identidades

AI 導讀

文章主張把自建及由第三方工具帶入的 AI 智能體都當作非人類身份審核,逐項檢查身份、權限、資料可達路徑和活動記錄。IAM 政策模擬顯示,即使角色不能透過 Secrets Manager API 讀取秘密,若可對生產 ECS 執行 ExecuteCommand,仍可能透過容器環境變數接觸資料庫、JWT 和 Stripe 憑證。作者建議部署流水線中的智能體使用獨立工作和角色,避免繼承部署憑證。

正文

Los agentes de IA son identidades no humanas. Algunos los despliegas tú mismo, y otros llegan con herramientas que ya usas.

Dos tipos de agente

Los agentes elegidos son los que están en tus diagramas: tú creaste el rol,
así que en principio le pusiste alcance. Los agentes heredados llegaron con
una funcionalidad de un proveedor. GitHub trae Dependabot, tu issue tracker trae
un summarizer, tu buzón recibe un asistente que conectaste en treinta segundos.
Nadie escribió un rol para ellos, porque su acceso es un grant de OAuth o una
instalación de GitHub App, no una policy de IAM.

Los dos tipos tienen una identidad, un conjunto de permisos, un camino de red
hacia las cosas, y actividad que podrías o no loguear. La revisión es la misma de
cualquier forma. Los agentes heredados nada más son más fáciles de olvidar,
porque ningún código de infraestructura los menciona.

Este post lo propuso un agente programado que lee un buzón a través de un conector
OAuth. Ese conector tiene más alcance hacia datos personales que cualquier cosa en
la cuenta de producción. Pertenece al mismo inventario.

La pregunta cara: qué pueden alcanzar los agentes

Los agentes de modelo: con alcance a propósito

El rol del intelligence service lista los ARNs de modelo exactos que puede
invocar:

// Restringir a los ARNs de modelo que de verdad usamos para que una tarea
// comprometida no pueda invocar modelos caros de escala Sonnet.
const bedrockModelArns = [
  `arn:aws:bedrock:${region}::foundation-model/amazon.nova-micro-v1:0`,
  `arn:aws:bedrock:${region}::foundation-model/amazon.nova-lite-v1:0`,
  `arn:aws:bedrock:${region}::foundation-model/amazon.nova-pro-v1:0`,
  `arn:aws:bedrock:${region}::foundation-model/amazon.titan-embed-text-v2:0`,
  "arn:aws:bedrock:us-west-2::foundation-model/stability.stable-image-core-v1:1",
  "arn:aws:bedrock:us-west-2::foundation-model/stability.stable-image-ultra-v1:1",
];

El backend, que también genera imágenes, no:

actions: ["bedrock:InvokeModel"],
resources: ["arn:aws:bedrock:*::foundation-model/stability.*"],

El wildcard fue deliberado: los modelos de imagen de Bedrock pasaron a Legacy tres
veces seguidas (Nova Canvas, Titan v2, SDXL), y cada una significó perseguir un
ARN nuevo. Sigue siendo cada modelo de Stability en cada región. Eso es una
exposición de costo, no una exposición de datos, y una alarma de budget sobre el
atributo de modelo es el control correcto para ello. En este caso la nueva
funcionalidad de Cost Explorer sí ayuda.

Los controles a nivel de prompt para estos agentes (agencia excesiva, inyección,
manejo de output).
Este post es sobre la identidad debajo de ellos.

El agente de código: con alcance en el papel

El grant de secretos dice:

// Solo credenciales de bootstrap. NO los secretos de la app (rds, stripe, jwt...).
new iam.PolicyStatement({
  sid: "ReadBootstrapSecrets",
  actions: ["secretsmanager:GetSecretValue"],
  resources: [
    `arn:aws:secretsmanager:${region}:${account}:secret:/myapp/agent-box-github-token-*`,
    `arn:aws:secretsmanager:${region}:${account}:secret:/myapp/agent-box-claude-credentials-*`,
  ],
}),

La escritura de vuelta es todavía más estrecha: PutSecretValue solo sobre las
credenciales, para que "una sesión desbocada no deba poder sobreescribir"
el token de GitHub. Cada statement es correcto. Más abajo, para depurar prod:

new iam.PolicyStatement({
  sid: "EcsExecAndRead",
  actions: ["ecs:ExecuteCommand", "ecs:DescribeServices", "ecs:DescribeTasks", /* ... */],
  resources: ["*"],
}),
new iam.PolicyStatement({
  sid: "EcsDeploy",
  actions: ["ecs:RegisterTaskDefinition", "ecs:UpdateService", "ecs:RunTask", "ecs:StopTask", "ecs:TagResource"],
  resources: ["*"],
}),

Pregúntale a IAM qué puede hacer el rol, en lugar de leer los statements uno por
uno:

aws iam simulate-principal-policy \
  --policy-source-arn "$AGENT_ROLE_ARN" \
  --action-names ecs:ExecuteCommand ecs:UpdateService ecs:RegisterTaskDefinition \
                 secretsmanager:GetSecretValue iam:PassRole \
  --resource-arns "*" \
  --query 'EvaluationResults[].[EvalActionName,EvalDecision]' --output text
ecs:ExecuteCommand  allowed
ecs:UpdateService   allowed
ecs:RegisterTaskDefinition  allowed
secretsmanager:GetSecretValue   implicitDeny
iam:PassRole    implicitDeny

GetSecretValue sobre * está denegado, que es lo que el comentario prometía.
ExecuteCommand sobre * está permitido, y el contenedor del backend de
producción recibe DB_USER/DB_PASSWORD, JWT_PRIVATE_KEY y STRIPE_SECRET_KEY
inyectados desde Secrets Manager como variables de entorno al arrancar. Un shell en
ese contenedor está a un env de distancia de cada secreto que el comentario dice
que el agente no puede leer. Ese camino se usa a propósito: las queries ad-hoc de
producción corren a través de ECS Exec a la tarea del backend. Es un manual de
operaciones documentado, no un hipotético.

iam:PassRole muestra implicitDeny solo porque la simulación no pasó ningún
contexto de iam:PassedToService. El statement real permite pasar cualquier rol
myapp-* a tareas de ECS, y junto con RegisterTaskDefinition y UpdateService
eso significa: correr cualquier imagen, bajo cualquier task role de app, como un
servicio de producción.

Los secretos tenían alcance. El alcance del agente no. El grant de secretos
responde "cuáles secretos puede leer a través de la API de secretos". El alcance es
la unión de cada camino hacia los datos, y aquí el camino más corto pasó por el
contenedor.

El agente que agregarías al pipeline

AWS Continuum for Penetration Testing (antes AWS Security Agent) entró a public
preview el 5 de octubre como un paso en tiempo de deploy: hallazgos en la salida
del pipeline, re-test automático después de un arreglo
(anuncio).
El anuncio no lista los permisos que necesita. Lee
la guía de CI/CD antes de implementarlo.

Lo que el anuncio sí deja claro es la colocación: el paso de deploy. En este stack,
la identidad del job de deploy puede desplegar infraestructura a través de la
cadena de bootstrap de CDK, que termina en AdministratorAccess. Pega un snippet de un proveedor en ese job
y el agente nuevo lo hereda todo, a través del entorno, sin que nadie escriba una
policy. Dale su propio job, su propio rol, y nada en su entorno que el snippet no
necesite. Un pentester necesita alcanzar la URL objetivo. No necesita tus
credenciales de deploy.

Una revisión para cada agente

Cuatro preguntas, en el mismo orden para agentes elegidos y heredados:

  1. Identidad. ¿Cuál principal es? ¿Un rol de IAM, un grant de OAuth, una GitHub App, un PAT? ¿Quién lo tiene, y cuándo expira su credencial? Un refresh token de OAuth que se muere del lado del servidor se lleva al agente con él, y solo un login humano lo puede traer de vuelta. El post de la parte 2 sobre la caja cubre cómo se ve eso.
  2. Permisos. Corre simulate-principal-policy contra las acciones que importan, en lugar de leer statements. Los comentarios describen la intención. El simulador describe la policy.
  3. Alcance. Para cada activo sensible, lista cada camino hacia él, no solo la API obvia. Los secretos alcanzan un proceso a través de la API de secretos, las variables de entorno, un shell en un contenedor que los contiene, el instance metadata service, un paso de CI que los imprime.
  4. Actividad. ¿Puedes distinguir sus llamadas de las de un humano? CloudTrail muestra el nombre de la sesión del rol. Nombra las sesiones, y para los conectores de OAuth checa qué loguea el proveedor. El conector del buzón de arriba no deja un rastro que el dueño del buzón pueda consultar.

El costo es la quinta pregunta, y la más barata. Respóndela al final.

Qué ayudaría después

  1. Divide el rol del agente de código por riesgo, no por servicio. Mantén la observabilidad de solo-lectura sobre *. Mueve ecs:ExecuteCommand y las acciones de deploy a un segundo rol que la caja asume bajo demanda con una sesión respaldada por MFA de un humano, o ponle alcance a ExecuteCommand con una condición ecs:cluster a un clúster que no sea de prod. Esto cuesta fricción en cada sesión de debug de prod. Esa fricción es el punto.
  2. Agrega un permission boundary a cada rol de agente. Un boundary no puede otorgar nada, así que es seguro escribirlo de forma amplia: niega iam:* excepto PassRole, niega secretsmanager:* fuera del prefijo del agente, niega ecs:ExecuteCommand sobre prod salvo que un session tag diga que un humano aprobó. Ejemplo en la carpeta de código.
  3. Inventaría los agentes heredados. Lista los grants de OAuth y las apps instaladas por herramienta (GitHub, Google Workspace, el issue tracker, el chat). Esto es una hoja de cálculo, no infraestructura. También es el único paso aquí sin código, que es por lo que sigue sin hacerse.
  4. Fija el ARN del modelo de imagen en el backend, o quédate con el wildcard y ponle un budget al atributo de modelo. Escoge uno y escribe la razón en el comentario.
  5. Corre la simulación de alcance en CI. Una prueba de contrato que falla si cualquier rol de agente nuevamente obtiene ecs:ExecuteCommand, iam:PassRole o secretsmanager:GetSecretValue sobre * atrapa las regresiones que la revisión se pierde.

Checklist

  • [ ] Cada agente, elegido o heredado, está listado con dueño, tipo de credencial y expiración.
  • [ ] Cada rol de agente se checó con simulate-principal-policy, no leyendo el JSON.
  • [ ] Ningún rol de agente tiene ecs:ExecuteCommand, ssm:StartSession o lambda:UpdateFunctionCode sobre producción sin un paso humano.
  • [ ] Cada rol de agente tiene un permission boundary.
  • [ ] Las sesiones de los roles de agente están nombradas, para que CloudTrail distinga agente de humano.
  • [ ] Los agentes de pipeline corren en su propio job, con su propio rol, sin credenciales de deploy en su entorno.
  • [ ] El gasto de agente se filtra sobre cada valor de SERVICE que vende modelos, no solo Amazon Bedrock.
  • [ ] Los grants de OAuth a funcionalidades de IA en herramientas SaaS se revisan en agenda.

來源:DEV Community · dev.to