El conector de AWS salió el 27 de octubre en KubeBolt 2.5, la versión open source. Antes de soltarlo lo probamos con diez incidentes en un laboratorio de EKS: una regla de red borrada, una clave KMS desactivada, una Lambda que deja de consumir. En cada uno, Kobi recibía la pregunta que haría un operador, sin pistas.
Lo más útil que dejaron esas pruebas es dónde va el arreglo cuando Kobi se equivoca: el dato va donde mira el modelo. Casi nunca fue una frase más en el prompt. Fue un dato puesto junto a lo que Kobi ya estaba leyendo.
Lo que hay debajo, en cinco líneas:
- Kobi no escribe código contra tu cuenta. Elige una operación de una lista, y KubeBolt hace la llamada con una sesión que no puede más que esa lista.
- Diez incidentes, todos probados en vivo. Cinco salieron a la primera pregunta, y los otros cinco necesitaron arreglos entre una vuelta y otra.
- Cuando Kobi se equivocaba, reescribir la skill no lo movía. Poner el dato junto al error, sí.
- La prueba más barata costó 32 créditos, y la mayoría, entre 50 y 100.
- El conector está en KubeBolt 2.5 open source. En KubeBolt Cloud todavía no.
El recorrido de una pregunta
El caso del laboratorio: orders-api deja de llegar a su base de datos, un PostgreSQL de RDS que el clúster alcanza por un nombre privado. Así va la pregunta desde el pod hasta la cuenta:
- ALa clasificación de la dirección
- BLa pista del conector y la guía de dependencias
- CLa skill aws-investigation
- DLas notas del gateway
- Logs del backend.
get_pod_logsda el timeout haciashop-db…:5432, con su inicio y su fin. - La dirección. El Service ExternalName lleva a
db.tienda.internal, un nombre privado. - La clasificación.
get_external_connectionslo reconoce como una zona privada de Route 53, con el conector disponible, y añade las instancias de los nodos. - La llamada tipada. Kobi pide servicio, operación y parámetros a
mcp__aws__call. Nunca código. - El script. El gateway comprueba la operación contra la lista, escribe el script y asume el rol del cliente con su external ID y una política de sesión.
- La lectura. El servidor MCP de AWS ejecuta el script en la cuenta, con la sesión asumida.
- La respuesta. Compactada por el gateway y sin valores de secretos: causa, quién y cuándo.
Como en Azure, Kobi no tiene una skill por servicio. Lo que sabe de AWS llega en cuatro capas, y dos de ellas viajan dentro del resultado de una herramienta, en el momento en que Kobi las necesita.
Kobi no escribe código contra tu cuenta
El servidor MCP de AWS no tiene modo de solo lectura: su herramienta ejecuta Python con la identidad de quien llama. Así que las protecciones están en KubeBolt y en el rol, y se repiten a propósito:
- líneas de código del modelo que lleguen a la cuenta
- 0
- familias de lectura, que aprueba el administrador
- 16
- llamadas a AWS como mucho por turno; el prompt le pide cinco
- 12
- El modelo no escribe códigoKobi pasa servicio, operación y parámetros a una herramienta tipada, y KubeBolt escribe el script que ejecuta el servidor de AWS.
- Una tabla, tres filtrosLa lista del gateway, la política de sesión y la política del rol salen de la misma tabla de familias, así que no pueden contradecirse.
- La sesión no puede más que la listaCada llamada asume el rol con una política de sesión. Aunque el rol del cliente tuviera ReadOnlyAccess, la sesión no pasa de la lista.
- Ni secretos ni datosEl rol niega los valores de Secrets Manager y Parameter Store, descifrar con KMS, los objetos de S3, las filas de DynamoDB y el código de una función.
- Lo que vuelve, limpioLas variables de entorno de una Lambda llegan con su nombre y el valor tapado, también en CloudTrail, igual que las credenciales de una respuesta.
- Nada más por el servidor MCPLa política del rol niega cualquier acción fuera de la lista cuando la llamada llega por el servidor MCP de AWS (aws:ViaAWSMCPService).
- Un external ID que nadie eligeKubeBolt lo genera para cada organización, y el administrador solo lo copia en la confianza del rol.
- Servicios enteros fueraLa Data API de RDS, los streams de DynamoDB y SSO no admiten ninguna operación, ni siquiera de lectura.
Diez incidentes
Cada incidente se rompió como pasaría de verdad, con el usuario del laboratorio y aws-cli, y se preguntó sin pistas. Una vuelta es una pregunta. Cuando hizo falta más de una, entre vuelta y vuelta cambió algo en KubeBolt.
- 01 1 + seguimiento
La regla de la base
Se borra la regla del security group de RDS que deja entrar a los pods.
Causa, autor y hora en una pregunta; la regla exacta, en el seguimiento.
Lee ec2 · rds · cloudtrail50 + 99 créditos
- 02 5 vueltas
La entrada desde Internet
Una regla de la network ACL deja fuera al ALB, y dentro del clúster todo sigue en verde.
Con los arreglos, causa, autor y hora en una pregunta y un seguimiento, también con el laboratorio recién creado.
Lee elbv2 · ec2 · cloudtrail97 y 115 créditos
- 03 3 vueltas
El rol sin su política
catalog-api pierde la política para leer su bucket, cifrado con una clave KMS propia.
La clave nombrada en la respuesta y comprobada en el seguimiento, con los dos permisos.
Lee iam · s3 · kms34 + 22 créditos
- 04 2 vueltas
La clave desactivada
S3 responde KMS.DisabledException, con un incidente anterior aún en los logs.
El segundo de tres cambios sobre la clave, separado del incidente anterior.
Lee kms · cloudtrail50 créditos
- 05 1 pregunta
La contraseña rotada
Secrets Manager rota la contraseña y los pods siguen con la vieja.
El RotateSecret correcto y el rollout restart en una pregunta, sin ver nunca el valor.
Lee secretsmanager · cloudtrail55 créditos
- 06 1 pregunta
Un reinicio de diez segundos
Se reinicia la RDS y la tienda falla unos segundos. Se pregunta después.
El reinicio, quién y cuándo, con la fuente de cada hecho.
Lee rds · cloudtrail56 créditos
- 07 1 pregunta
La imagen que no se descarga
La política del repositorio de ECR deja fuera al rol de los nodos.
La política, su autor y el ARN del rol escrito sin su path.
Lee ecr · iam · cloudtrail32 créditos
- 08 3 vueltas
El registro DNS
El CNAME privado de la base apunta a una instancia que no existe.
El registro en la primera respuesta y la instancia que falta, en el seguimiento.
Lee route53 · ec2 · rds88 créditos
- 09 1 pregunta
Un nodo que desaparece
Se termina una instancia del node group, con las dos réplicas de CoreDNS dentro.
El autor, el reemplazo y el hueco de DNS, con la propuesta de repartir CoreDNS.
Lee eks · autoscaling · cloudtrail57 créditos
- 10 2 vueltas
Los pedidos que no se confirman
La Lambda que confirma pedidos queda con concurrencia 0. La cola y su DLQ crecen.
La DLQ leída y el arreglo en dos pasos; el autor, en el seguimiento.
Lee sqs · lambda · cloudtrail67 + 39 créditos
El laboratorio tiene un cerco que una cuenta real no tendría: niega CloudTrail en us-east-1, donde AWS registra los cambios de IAM y de Route 53. Por eso en dos pruebas Kobi no pudo nombrar al autor, y lo dijo.
De cerca: la contraseña rotada
Es el mejor ejemplo de por qué Kobi tiene que salir del clúster. La causa está en AWS, el fallo se ve en el clúster, y el arreglo no es el que parece: el Secret ya tiene la contraseña nueva, pero los pods la leyeron al arrancar.
El dato va donde mira el modelo
La prueba del rol lo enseña mejor que ninguna. catalog-api lee de S3 con su propio rol, y el bucket cifra con una clave KMS propia. Alguien desadjunta la política del rol. El error de la app nombra la acción que falló primero, s3:GetObject, y no dice que leer ese objeto exige también kms:Decrypt sobre la clave.
Lo primero fue lo de siempre: reescribir la skill de AWS para que lo dijera. Kobi la cargó y dio la misma respuesta. Así que el dato fue a donde está el error:
Lo que Kobi tenía delante, en los logs de catalog-api
… is not authorized to perform: s3:GetObject on resource: …/featured.json Lo que get_pod_logs pone ahora junto a esa línea
"awsDenials": [{
"action": "s3:GetObject",
"resource": "arn:aws:s3:::…/featured.json",
"alsoGuardedBy": "An S3 object is also guarded by its bucket's policy
(s3 GetBucketPolicy) and by the bucket's default encryption
(s3 GetBucketEncryption). With SSE-KMS under a customer-managed key,
reading an object also needs kms:Decrypt on that key, …"
}] - 1.ª vuelta Propone devolver solo s3:GetObject. La lectura habría seguido fallando, ahora por la clave.
- 2.ª vuelta, con la skill reescrita Carga la skill y da la misma respuesta. La frase nueva no cambió nada.
- 3.ª vuelta, con awsDenials Nombra kms:Decrypt en la respuesta. En el seguimiento lee la clave y da los dos permisos.
No fue un caso aislado. Casi todos los arreglos del laboratorio siguieron la misma regla:
| Dónde se equivocó Kobi | Lo que KubeBolt pone ahora donde mira |
|---|---|
| Una negativa de Route 53 le hizo dar el servicio por perdido | Tras un AccessDenied, una nota: AWS negó una operación, no el servicio, y estas son las otras habilitadas |
| La regla, borrada por su id, no salía en CloudTrail | CloudTrail guarda también la respuesta de cada cambio, con la regla completa |
| Buscó la clave KMS por su id y no encontró el cambio | Una nota: el DisableKey nombra la clave por su ARN |
| Dio por vacía una DLQ con unos 404 pedidos dentro | GetQueueAttributes lleva una nota cuando la cola tiene DLQ |
| Leyó 185 copias de la misma línea de log | Las líneas iguales salvo la hora salen una vez, con cuántas eran y desde cuándo |
| Tomó un evento que sumaba dos episodios por el inicio del corte | Un evento con más de 30 minutos entre su primera y su última aparición lleva ese tramo y una nota |
Ninguna es una regla nueva en el prompt. Cada fallo se podía tapar con una frase más, y así es como engordan los prompts. Un dato no compite con el error que el modelo tiene delante, porque está a su lado.
De cerca: la clave desactivada
Esta prueba puso dos de esos datos a trabajar a la vez. En la misma hora había tres tramos de error en los logs, dos de ellos de la misma clave, y tres cambios sobre ella en CloudTrail. Con las mismas cinco llamadas, la segunda vuelta llegó más lejos porque las respuestas traían las notas: la de la búsqueda por id y la hora de cada denegación.
- 1 DescribeKey KeyState: Disabled
- 2 CloudTrail por el id solo su creación
- 3 CloudTrail por origen Decrypt fallidos
- 4 SimulatePrincipalPolicy deny falso, sin región
- 5 CloudTrail, escrituras DisableKey 16:31:43
Causa, autor y hora en una pregunta, pero tres de las cinco llamadas le contestaron de forma engañosa.
- 1 DescribeKey KeyState: Disabled
- 2 CloudTrail por el id vacío, con la nota
- 3 CloudTrail por el ARN los tres cambios
- 4 CloudTrail, escrituras repite lo que tenía
- 5 El rol, en us-east-1 AccessDenied del cerco
Los tres cambios y, como causa, el segundo DisableKey. Las dos últimas llamadas sobraron.
Cuando un agente se equivoca, decirle más cosas casi nunca lo arregla. Poner el dato que le faltaba donde ya está mirando, sí.
Lo que todavía falla
La lista de huecos que salió del laboratorio tiene más entradas de las que cuento aquí. Dos de las que menos me preocupan:
- Comprobar antes de proponer. Cuando la causa le parece clara, Kobi a veces deja sin hacer una lectura que tiene permitida y para la que le sobran llamadas, como confirmar la versión actual de un secreto antes de proponer un reinicio. Lo dice y lo ofrece como opción, pero no lo comprueba.
- La zona horaria al pedir a CloudTrail. Con horas en dos zonas distintas, Kobi pidió a CloudTrail una ventana desplazada y se le escapó el cambio. Pasa sobre todo en desarrollo, con la API en hora local.
Lo que todavía no es
El conector está en KubeBolt 2.5, la versión open source. Hoy KubeBolt asume el rol del cliente desde la identidad con la que corre, y eso sirve en instalaciones propias. En KubeBolt Cloud todavía no está.
Lo que queda
Diez incidentes dejaron una regla corta: el dato va donde mira el modelo. Con eso, un conector de solo lectura sirve para algo. Kobi lee tu cuenta sin escribir una línea de código, y lo que lee le llega con lo que necesita para no equivocarse.