Skip to content

Attestation

Attestation is the material the control-plane verifies at enrollment to decide which tenant this runner belongs to. You choose it with RUNNER_ATTESTATION_MODE.

Mode Status Where to use it
bootstrap-token default Development and proofs of concept. It’s the weakest link: a secret someone has to mint and hand over.
aws-sts implemented EC2, EKS, or a laptop authenticated with aws sso login.
gke-oidc implemented GKE with Workload Identity.
eks-oidc not implemented Nowhere. On EKS, use aws-sts.
Terminal window
RUNNER_ATTESTATION_MODE=bootstrap-token
RUNNER_BOOTSTRAP_TOKEN=<token minted per tenant>

The token is minted per tenant, and it is what pins which organization the runner joins. Without it, boot fails fast with its own message:

RUNNER_ATTESTATION_MODE=bootstrap-token requires RUNNER_BOOTSTRAP_TOKEN

That fail-fast exists because the alternative is worse: without it the runner boots, tries to enroll, takes a 401, and enters a reconnect loop, an error that looks like networking and is credentials.

Terminal window
RUNNER_ATTESTATION_MODE=aws-sts
AWS_REGION=us-east-1

This is the mode that closes the cold-start problem for a fleet: with an AWS identity there is no token to mint by hand, so bringing the fleet up stops requiring a human in a browser.

The runner pre-signs an sts:GetCallerIdentity request (Vault’s IAM-auth style) and sends the parts (signed headers, body, and region), never a URL. The control-plane executes the call against an STS endpoint from its own allowlist and reads the ARN from the response.

Two properties follow:

  • AWS validates the signature. The control-plane signs nothing and cannot be tricked into calling an arbitrary host: it’s anti-SSRF by construction.
  • Nothing secret travels. The SigV4 signature proves possession of the credential without revealing it, and the X-Amz-Security-Token accompanying temporary credentials is already public by construction.

The credential comes from the SDK’s default chain: environment variables, the SSO cache, IRSA on EKS, IMDS on EC2.

RUNNER_ATTESTATION_MODE=aws-sts requires AWS_REGION

The region is not guessed, on purpose: the control-plane only accepts regions from its own allowlist, and a wrong guess would surface as an attestation_invalid that reads like a credential problem. The default allowlist covers us-east-1, us-west-2 and sa-east-1; if your cluster runs outside them, talk to us before the first boot. As long as it’s the commercial partition, it’s configuration on our side. The refusal names the accepted regions, so you can confirm from the error.

GovCloud and China are not supported: they’re different AWS partitions, with their own endpoint and ARN formats.

Terminal window
RUNNER_ATTESTATION_MODE=gke-oidc
# RUNNER_GKE_TOKEN_PATH=/var/run/secrets/tokens/gke-oidc/token # default

The runner reads the projected OIDC token of the Kubernetes ServiceAccount and sends it as attestation. Nothing secret enters the image: the token is a short-lived, audience-bound JWT projected by the kubelet. The control-plane verifies it against Google’s JWKS and maps the KSA and project to the tenant.

The pod needs a projected volume with a serviceAccountToken mounted exactly at the configured path, projected for the audience the control-plane requires:

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

The audience is the replay defense: without it, a KSA token projected for any other service would be good enough to enroll. That’s why verification is fail-closed: a missing or different audience is refused, and the refusal arrives as attestation_invalid, indistinguishable from a bad credential. It’s the first field to check when an enroll fails with an apparently correct KSA.

If it’s missing, the error says so:

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?)

And if the file exists but is empty:

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

Certificate renewal uses its own attestation, mtls-renewal, which is not a configurable mode. See Enrollment and mTLS.