Skip to content
HelicarrierDevelopers
DOCUMENTATION

Workload identity (OIDC)

Give a service short-lived AWS, Google Cloud or Azure credentials through OIDC federation, instead of storing long-lived cloud keys as variables.

A cloud key stored as a variable never expires: if it leaks, it works until someone disables it. With workload identity, nothing long-lived is stored with Helicarrier. Your service gets a short-lived signed token, and your cloud trades it for short-lived credentials at runtime.

  • Each service that turns it on becomes its own OIDC issuer: https://<your dashboard host>/oidc/<service id>, with its own signing key, its own discovery document and its own JWKS.
  • Helicarrier writes a token to /var/run/heli/oidc-token inside the container (read-only) and refreshes it before it expires. It is never an environment variable.
  • The token’s subject names exactly one service: account:<account id>:project:<project id>:service:<service id>:env:<environment id>. It carries one audience — the value your cloud expects — and lives 15 minutes by default (5–60).

It is off for every service until you turn it on. Turning it on takes effect at the service’s next deploy.

The token is a file inside the container, so anything that runs in the container can read it — that is the point. It follows that anyone who can change what runs there can get it too: whoever can change the service’s image, source, build settings, start command or deploy hooks, or open a shell in it, can have the next deploy hand them a token and trade it for your cloud credentials.

So workload identity is not a separate credential that someone with deploy rights lacks. A teammate, or an API key scoped to this service, that can deploy it is effectively a holder of whatever cloud role trusts it. Grant the role only what the service itself needs, and treat deploy access to the service as access to that role.

What it does remove: there is no long-lived key to leak from a variable, a log, a backup or a laptop. A token that escapes works for at most its lifetime (15 minutes by default) and only for the one audience and role that trust this service.

Terminal window
curl -X PUT https://app.helicarrier.xyz/api/services/<service id>/workload-identity \
-H "Authorization: Bearer $HELI_API_KEY" -H "Content-Type: application/json" \
-d '{"enabled": true, "audience": "sts.amazonaws.com"}'

The response shows the issuer and subject to put into your cloud’s trust configuration. Then redeploy the service.

POST /api/services/<id>/workload-identity/rotate rotates the signing key. The old key stays published until every token it signed has expired, so nothing breaks.

  1. Create an IAM OIDC identity provider with Provider URL = your service’s issuer and Audience = sts.amazonaws.com.
  2. Create a role with this trust policy (one service’s subject only):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::<aws account>:oidc-provider/<dashboard host>/oidc/<service id>" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<dashboard host>/oidc/<service id>:aud": "sts.amazonaws.com",
"<dashboard host>/oidc/<service id>:sub": "account:<account id>:project:<project id>:service:<service id>:env:<environment id>"
}
}
}]
}
  1. Set two variables on the service: AWS_ROLE_ARN=<the role's ARN> and AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/heli/oidc-token. Every AWS SDK picks those up and refreshes credentials on its own.

Google Cloud: Workload Identity Federation

Section titled “Google Cloud: Workload Identity Federation”
Terminal window
gcloud iam workload-identity-pools create helicarrier --location=global
gcloud iam workload-identity-pools providers create-oidc svc-<service id> \
--location=global --workload-identity-pool=helicarrier \
--issuer-uri="https://<dashboard host>/oidc/<service id>" \
--allowed-audiences="https://iam.googleapis.com/projects/<project number>/locations/global/workloadIdentityPools/helicarrier/providers/svc-<service id>" \
--attribute-mapping="google.subject=assertion.sub" \
--attribute-condition="assertion.sub == 'account:<account id>:project:<project id>:service:<service id>:env:<environment id>'"
gcloud iam service-accounts add-iam-policy-binding <sa>@<gcp project>.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principal://iam.googleapis.com/projects/<project number>/locations/global/workloadIdentityPools/helicarrier/subject/account:<account id>:project:<project id>:service:<service id>:env:<environment id>"

Turn workload identity on with that allowed-audiences value as the audience. Generate a credential configuration (gcloud iam workload-identity-pools create-cred-config … --credential-source-file=/var/run/heli/oidc-token), store it as a secret file (it holds no secret), and point GOOGLE_APPLICATION_CREDENTIALS at it.

On an app registration or a user-assigned managed identity, add a federated credential:

Terminal window
az identity federated-credential create --name svc-<service id> \
--identity-name <identity> --resource-group <rg> \
--issuer "https://<dashboard host>/oidc/<service id>" \
--subject "account:<account id>:project:<project id>:service:<service id>:env:<environment id>" \
--audiences "api://AzureADTokenExchange"

Turn workload identity on with api://AzureADTokenExchange as the audience, and set AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE=/var/run/heli/oidc-token. The Azure SDKs’ DefaultAzureCredential uses them.

  • Turning it off removes the token from the container’s machine at once. Tokens already handed out still verify until they expire: the issuer keeps publishing its keys for that long, then stops. Turning it back on resumes in the same place, so a running container sees new tokens without a redeploy.
  • Transferring the project to another account gives the service a new signing key and withdraws the old ones at once, so no token signed for the previous owner verifies after the transfer. The new owner’s tokens name their own account in sub. Always require sub in your trust policy: it is what ties the role to one service of one account.
  • Deleting a service stops its tokens; restoring it from the trash resumes them. Purging it removes its signing keys for good.
  • One audience per service. To federate the same service with two clouds, use two services, or tell us — that is on the list.
  • Available on Helibox (the default engine), on the control plane and on nodes.
  • Managed databases don’t get tokens.