Ir al contenido

Credenciales de nube

Los connectors de AWS y GCP necesitan credenciales de nube para leer. Hay dos modos, y son ortogonales al secret store: aquel decide dónde viven los secretos, este decide cómo se resuelven las credenciales de nube.

Ventana de terminal
RUNNER_AWS_CRED_MODE=static # default
RUNNER_AWS_CRED_MODE=chain
RUNNER_GCP_CRED_MODE=static # default
RUNNER_GCP_CRED_MODE=chain

Lee AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY y, opcionalmente, AWS_SESSION_TOKEN del secret store y los inyecta explícitamente en el cliente.

Sirve a quien recibe claves ya hechas o las guarda en Vault o en Secrets Manager. Es el modo por defecto por retrocompatibilidad.

No inyecta ninguna clave. La resuelve la cadena de credenciales por defecto del SDK: IRSA en EKS, task role en ECS, instance profile en EC2, variables de entorno o la caché de SSO.

Es el modo correcto cuando el runner corre dentro de AWS, y es lo que mantiene las claves estáticas fuera de circulación.

Ventana de terminal
RUNNER_AWS_CRED_MODE=chain
AWS_PROFILE=my-profile # in development, with aws sso login

Una sutileza que provoca un connector invisible

Sección titulada «Una sutileza que provoca un connector invisible»

El served set es secret-aware: un connector al que le faltan las claves obligatorias sale del conjunto anunciado. Pero en el modo chain la credencial no viene del secret store, así que, sin un tratamiento especial, el runner no anunciaría las operaciones aws.* aunque funcionaran perfectamente.

Por eso el runtime marca el connector aws como siempre servido en el modo chain. Vale la pena saber que existe este caso especial, para que la diferencia de comportamiento entre los dos modos no te sorprenda.

El modo chain es de una sola cuenta por construcción. Para varias cuentas de AWS, ejecuta un runner por cuenta, cada uno con su propia identidad IRSA. El grafo se fusiona del lado del control-plane.

Con RUNNER_CONNECTORS=real, el runner hace un sondeo best-effort de STS en el boot para descubrir la cuenta y la región, y lo reporta en el handshake. Es lo que permite al control-plane resolver el contexto de AWS del tenant a partir del runner vivo, en lugar de configuración manual.

El sondeo nunca lanza excepciones. Si falla, la información simplemente no se envía, y el control-plane usa su fallback.

El diseño es el hermano exacto del lado de AWS.

Lee la clave JSON de la service account (GCP_SA_KEY, el JSON en una sola línea) del secret store y construye los clientes con ella.

No inyecta ninguna clave. La resuelve ADC: Workload Identity en GKE, metadata en GCE, el archivo al que apunta GOOGLE_APPLICATION_CREDENTIALS, o gcloud.

Con chain, no hace falta GCP_SA_KEY.

Ventana de terminal
RUNNER_GCP_CRED_MODE=chain
GCP_PROJECT_ID=my-project

También es de un solo proyecto: para varios proyectos, un runner por proyecto, cada uno con su propia GSA de Workload Identity.

Aquí el diseño no es hermano de los otros dos, y la diferencia es de postura, no de conveniencia.

MGC se autentica con una API key (header X-API-Key). No hay un análogo de cadena de credenciales (nada equivalente a IRSA en AWS o a Workload Identity en GCP), así que no existe RUNNER_MGC_CRED_MODE: solo la clave estática, leída del secret manager del cliente. Inventar un modo que no existe sería peor que la ausencia.

Ventana de terminal
MGC_API_KEY=…
MGC_REGION=br-se1 # optional; the region lives in the URL, one runner serves one region
MGC_TENANT_ID=… # optional; saves one call at boot
MGC_S3_ACCESS_KEY=… # object storage; the `key_pair_id` of the SAME key
MGC_S3_SECRET_KEY=… # object storage; the `key_pair_secret` of the SAME key

Los alcances son el control, y son inmutables

Sección titulada «Los alcances son el control, y son inmutables»

Una API key de MGC lleva tres componentes: api_key (lo que WhyStack envía en el header X-API-Key), key_pair_id y key_pair_secret, que juntos son la credencial S3 de Object Storage y se convierten en los MGC_S3_ACCESS_KEY/MGC_S3_SECRET_KEY de arriba.

Crear la clave desde la consola con “todo” marcado genera unos 160 alcances sobre toda la cuenta, billing e IAM incluidos. Créala desde la CLI con --scopes explícitos y concede acceso de solo lectura, un alcance de lectura por cada producto que WhyStack va a leer:

Producto Qué se lee
Virtual machine (virtual-machine.read) instancias y sus IPs
Network (network.read) VPCs, subnets, security groups, IPs públicas, NAT, load balancers
Object storage (object-storage.read) buckets y postura de exposición
Block storage volúmenes, asociación y cifrado
DBaaS instancias, clústeres y réplicas de bases de datos
Kubernetes (MKE) clústeres, node pools y quién puede alcanzar el API server
Container registry registries, repositorios e imágenes
Auditoría quién hizo qué, cuándo y sobre qué recurso

Los identificadores de los cuatro últimos salen de la propia lista de alcances de la consola/CLI. No los adivines a partir de los tres primeros. Una clave sin el alcance de un producto no rompe WhyStack: solo las lecturas de ese producto vuelven con auth_error, y el resto del connector sigue sirviendo. En la práctica, el producto simplemente se vuelve invisible sin hacer ruido, así que vale la pena comparar la tabla de arriba con lo que esperas ver.

Eso es mejor de lo que parece: la postura de solo lectura de WhyStack pasa a estar aplicada en la credencial, no solo en el código. El connector rechaza escrituras, y la clave ni siquiera las permite. Los alcances no se pueden editar después: si la necesidad cambia, vuelve a crear la clave.

El análogo de “cuenta” en MGC es el tenant_id, que aparece en VPCs, security groups e IPs públicas. No existe “proyecto”.

A diferencia de GCP, no sale gratis: la API key es opaca, y no hay metadata server de workload identity. Por eso el runner usa MGC_TENANT_ID cuando está definido y, si no, lo deriva de un listado de VPCs (best-effort). Sin clave, sin VPC o con la llamada fallando, no se anuncia ninguna cuenta y el control-plane recurre a la configuración. Nunca inventa un id: anunciar una cuenta inexistente enviaría lecturas a un lugar que no responde.

Variable Notas
AWS_REGION La usan los connectors de AWS y es obligatoria para la atestación aws-sts.
MGC_API_KEY API key de Magalu Cloud. Créala con alcances de lectura, uno por cada producto que WhyStack va a leer (ver la tabla de arriba).
MGC_REGION br-se1 (por defecto) o br-ne1. Vive en la URL: un runner atiende una región.
MGC_TENANT_ID Evita la llamada de descubrimiento en el boot. Recomendado en producción.
MGC_S3_ACCESS_KEY El key_pair_id de la misma API key. Object storage habla S3 (SigV4) contra otro host: otra credencial, mismo dueño. Opcional: sin ella, los buckets quedan invisibles, sin error en el boot.
MGC_S3_SECRET_KEY El key_pair_secret de la misma API key. Lo que autoriza las lecturas de buckets es el alcance object-storage.read de MGC_API_KEY, no este par.
EKS_CLUSTER Sin ella, el health check de EKS responde skipped: no cluster configured. El connector aparece como no configurado en la Flota, que es distinto de roto e igual de ciego.
GCP_PROJECT_ID Proyecto de destino.
GCP_REGION Región de destino.
GCP_BILLING_EXPORT_TABLE Tabla de billing export de BigQuery. Sin ella, la operación de costos de GCP falla de forma explícita.