Ir al contenido

Atestación

La atestación es el material que el control-plane verifica en el enrollment para decidir a qué tenant pertenece este runner. La eliges con RUNNER_ATTESTATION_MODE.

Modo Estado Dónde usarlo
bootstrap-token por defecto Desarrollo y pruebas de concepto. Es el eslabón más débil: un secreto que alguien tiene que emitir y entregar.
aws-sts implementado EC2, EKS o una laptop autenticada con aws sso login.
gke-oidc implementado GKE con Workload Identity.
eks-oidc no implementado En ningún lado. En EKS, usa aws-sts.
Ventana de terminal
RUNNER_ATTESTATION_MODE=bootstrap-token
RUNNER_BOOTSTRAP_TOKEN=<token minted per tenant>

El token se emite por tenant, y es lo que fija a qué organización se une el runner. Sin él, el boot falla rápido con su propio mensaje:

RUNNER_ATTESTATION_MODE=bootstrap-token requires RUNNER_BOOTSTRAP_TOKEN

Ese fail-fast existe porque la alternativa es peor: sin él, el runner arranca, intenta hacer el enrollment, recibe un 401 y entra en un bucle de reconexión, un error que parece de red y es de credenciales.

Ventana de terminal
RUNNER_ATTESTATION_MODE=aws-sts
AWS_REGION=us-east-1

Este es el modo que resuelve el problema de cold start de una flota: con una identidad de AWS no hay token que emitir a mano, así que levantar la flota deja de requerir a un humano frente a un navegador.

El runner prefirma una solicitud sts:GetCallerIdentity (al estilo del IAM auth de Vault) y envía las partes (headers firmados, body y región), nunca una URL. El control-plane ejecuta la llamada contra un endpoint de STS de su propia allowlist y lee el ARN de la respuesta.

De ahí se desprenden dos propiedades:

  • AWS valida la firma. El control-plane no firma nada y no se le puede engañar para que llame a un host arbitrario: es anti-SSRF por construcción.
  • No viaja nada secreto. La firma SigV4 prueba la posesión de la credencial sin revelarla, y el X-Amz-Security-Token que acompaña a las credenciales temporales ya es público por construcción.

La credencial viene de la cadena por defecto del SDK: variables de entorno, la caché de SSO, IRSA en EKS, IMDS en EC2.

RUNNER_ATTESTATION_MODE=aws-sts requires AWS_REGION

La región no se adivina, a propósito: el control-plane solo acepta regiones de su propia allowlist, y una suposición equivocada aparecería como un attestation_invalid que se lee como un problema de credenciales. La allowlist por defecto cubre us-east-1, us-west-2 y sa-east-1; si tu clúster corre fuera de ellas, háblanos antes del primer boot. Mientras sea la partición comercial, es configuración de nuestro lado. El rechazo nombra las regiones aceptadas, así que puedes confirmarlo en el error.

GovCloud y China no están soportadas: son particiones distintas de AWS, con sus propios formatos de endpoint y de ARN.

Ventana de terminal
RUNNER_ATTESTATION_MODE=gke-oidc
# RUNNER_GKE_TOKEN_PATH=/var/run/secrets/tokens/gke-oidc/token # default

El runner lee el token OIDC proyectado de la ServiceAccount de Kubernetes y lo envía como atestación. No entra nada secreto en la imagen: el token es un JWT de vida corta, ligado a una audiencia y proyectado por el kubelet. El control-plane lo verifica contra el JWKS de Google y mapea la KSA y el proyecto al tenant.

El pod necesita un volumen projected con un serviceAccountToken montado exactamente en la ruta configurada, proyectado para la audiencia que exige el control-plane:

volumes:
- name: whystack-token
projected:
sources:
- serviceAccountToken:
path: token
audience: whystack-enroll
expirationSeconds: 3600

La audiencia es la defensa contra el replay: sin ella, un token de KSA proyectado para cualquier otro servicio serviría para hacer el enrollment. Por eso la verificación es fail-closed: una audiencia ausente o distinta se rechaza, y el rechazo llega como attestation_invalid, indistinguible de una credencial inválida. Es el primer campo que hay que revisar cuando un enroll falla con una KSA aparentemente correcta.

Si falta, el error lo dice:

RUNNER_ATTESTATION_MODE=gke-oidc: failed to read projected KSA token at
/var/run/secrets/tokens/gke-oidc/token (is the Workload Identity token volume mounted?)

Y si el archivo existe pero está vacío:

RUNNER_ATTESTATION_MODE=gke-oidc: projected token at … is empty

La renovación del certificado usa su propia atestación, mtls-renewal, que no es un modo configurable. Ver Enrollment y mTLS.