Skip to main content

Documentation Index

Fetch the complete documentation index at: https://ona.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Available on the Enterprise plan. Contact sales to learn more.
Ona environments can access Azure resources using workload identity federation. You configure a federated credential on an Azure app registration or user-assigned managed identity that trusts Ona’s OIDC tokens. Environments exchange their JWT for an Azure access token without storing any secrets.

Azure-specific constraints

Azure Entra ID federated credentials have two limits that shape how you design the trust:
  • Exact match on subject — wildcards are not supported. You need one federated credential per distinct sub value you want to authorize.
  • Maximum 20 federated credentials per app registration or managed identity.
Reference: Microsoft — Federated identity credential considerations. Plan the sub claim composition before creating credentials so the number of subs you need stays comfortably under 20.

Prerequisites

  • V3 tokens enabled on the OIDC Token Configuration page. See Enable V3 tokens.
  • Azure CLI installed in your environment.
  • An Azure app registration or user-assigned managed identity. The examples below use an app registration; the same federated-credential and CLI flow works for managed identities.

How it works

  1. Ona issues a JWT signed with RS256, containing identity claims about the environment, user, or service account.
  2. Azure validates the token against Ona’s OIDC discovery endpoint and JWKS.
  3. If iss, aud, and sub match the federated credential, Azure issues a service principal access token.
  4. The Azure CLI or any Azure SDK uses that access token to call Azure APIs.

Step 1: Create an app registration or managed identity

Use either an app registration or a user-assigned managed identity. Note the client ID and tenant ID — both are required for the login flow. App registration:
az ad app create --display-name ona-environment
# Note the appId returned — this is your --client-id.
User-assigned managed identity:
az identity create \
  --name ona-environment \
  --resource-group <RESOURCE_GROUP> \
  --location <LOCATION>

Step 2: Inspect your Ona token

Run this in an Ona environment to see what sub value Azure will need to match:
ona idp token --audience api://AzureADTokenExchange --decode
Record the sub value verbatim — Azure requires an exact-match string.

Step 3: Add a federated identity credential

Add a federated identity credential that trusts Ona’s OIDC tokens for the recorded sub. For an app registration:
az ad app federated-credential create \
  --id <CLIENT_ID> \
  --parameters '{
    "name": "ona-project-access",
    "issuer": "https://app.gitpod.io",
    "subject": "organization_id:<ORG_ID>:project_id:<PROJECT_ID>",
    "audiences": ["api://AzureADTokenExchange"]
  }'
For a user-assigned managed identity:
az identity federated-credential create \
  --name ona-project-access \
  --identity-name ona-environment \
  --resource-group <RESOURCE_GROUP> \
  --issuer https://app.gitpod.io \
  --subject "organization_id:<ORG_ID>:project_id:<PROJECT_ID>" \
  --audiences api://AzureADTokenExchange
FieldValue
issuerhttps://app.gitpod.io
subjectThe exact sub value from your Ona token
audiencesapi://AzureADTokenExchange
The subject must match the sub claim exactly, including case and order of key/value pairs. New federated credentials take a few minutes to propagate; token exchange may fail with AADSTS70021 during this window.

Step 4: Assign Azure RBAC roles

Grant the app registration or managed identity access to the Azure resources it needs:
az role assignment create \
  --assignee <CLIENT_ID> \
  --role "Key Vault Secrets User" \
  --scope /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.KeyVault/vaults/<VAULT_NAME>

Step 5: Authenticate from an environment

Use ona idp login azure to exchange the OIDC token and configure the Azure CLI:
ona idp login azure \
  --client-id <CLIENT_ID> \
  --tenant-id <TENANT_ID>
To set an active subscription as part of the login:
ona idp login azure \
  --client-id <CLIENT_ID> \
  --tenant-id <TENANT_ID> \
  --subscription-id <SUBSCRIPTION_ID>
Subsequent az calls use the federated credentials:
az keyvault secret show --vault-name my-vault --name my-secret

Flags

FlagRequiredEnv varNotes
--client-idyesIDP_AZURE_CLIENT_IDApp registration or managed identity client ID
--tenant-idyesIDP_AZURE_TENANT_IDDirectory (tenant) ID
--subscription-idnoIDP_AZURE_SUBSCRIPTION_IDIf set, becomes the active subscription after login
--audiencenoDefaults to api://AzureADTokenExchange

Automate on environment startup

Add the login to your automations:
# automations.yaml
tasks:
  azure-login:
    name: Azure Login
    command: ona idp login azure --client-id <CLIENT_ID> --tenant-id <TENANT_ID>
    triggeredBy:
      - postDevcontainerStart

Manual exchange (without ona idp login azure)

Use this when integrating with non-CLI tooling or other Azure SDKs:
TOKEN=$(ona idp token --audience api://AzureADTokenExchange)

az login --service-principal \
  --username <CLIENT_ID> \
  --tenant <TENANT_ID> \
  --federated-token "$TOKEN"
Or call Microsoft’s token endpoint directly:
TOKEN=$(ona idp token --audience api://AzureADTokenExchange)

curl -X POST "https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token" \
  -d "client_id=<CLIENT_ID>" \
  -d "scope=https://management.azure.com/.default" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=$TOKEN" \
  -d "grant_type=client_credentials"
For programmatic access in Python, the Azure Identity SDK accepts a token-fetching callable via ClientAssertionCredential:
import subprocess
from azure.identity import ClientAssertionCredential

def get_ona_token() -> str:
    return subprocess.run(
        ["ona", "idp", "token", "--audience", "api://AzureADTokenExchange"],
        capture_output=True, text=True, check=True,
    ).stdout.strip()

credential = ClientAssertionCredential(
    tenant_id="<TENANT_ID>",
    client_id="<CLIENT_ID>",
    func=get_ona_token,
)

Sub claim strategy

Azure’s exact-match constraint means you should pick the coarsest sub that still expresses your trust boundary. Each unique sub you want to authorize costs one of your 20 federated credentials per identity. The default V3 environment sub depends on whether the environment belongs to a project:
  • With project: organization_id:<orgID>:project_id:<projID> — stable across all environments in the project.
  • Without project: organization_id:<orgID> — matches every environment in the org.
Pick one of the patterns below. sub = organization_id + project_id (default — no configuration needed).
organization_id:<orgID>:project_id:<projID>
Federated credentialsUse case
1 per projectAll users in a project assume the same Azure role. Simplest setup, stays well within the 20-credential limit.

Per-user, per-project

Add creator_email (or creator_id) to the extra sub fields on the OIDC Token Configuration page. The sub becomes:
organization_id:<orgID>:project_id:<projID>:creator_email:user@example.com
Federated credentialsUse case
1 per user × projectDifferent users get different Azure permissions within the same project. Watch the 20-credential limit.

Per-user, all projects

Add user_id (for user tokens) or creator_id (for environment tokens) to the extra sub fields.
organization_id:<orgID>:user_id:<userID>
Federated credentialsUse case
1 per userUser-level Azure role assumption across all projects.

Per-repository

Add environment_initializers.git.remote_uri to the extra sub fields. Useful when you want the trust to follow a repository regardless of which Ona project wraps it.
organization_id:<orgID>:project_id:<projID>:environment_initializers.git.remote_uri:https%3A//github.com/org/repo.git
Colons in values are URL-encoded as %3A in the sub claim.
See Customizing the sub claim for the full list of fields you can add.

Limits

  • Maximum 20 federated credentials per app registration or managed identity. If you need more, create additional identities with different role assignments.
  • The subject field has a 600-character limit. Long sub compositions (many extra fields with UUIDs) can approach this.

Token claims available to your application

Even though Azure only matches against sub, the rest of the JWT body is available to your application after login. Use top-level claims for downstream authorization (audit logs, tenant routing, group-based checks).
ClaimDescription
organization_idOna organization UUID
project_idOna project UUID, when the environment is project-scoped
environment_idEnvironment UUID (changes per environment)
runner_idRunner UUID
creator_idOna user UUID of the creator
creator_principaluser or service_account
creator_emailEmail of the user who created the environment
creator_nameDisplay name of the creator
creator_idpURL of the creator’s identity provider
creator_idp_claimsNon-sensitive claims forwarded from the SSO provider
environment_initializersGit remote and context URL the environment was created from
See Token structure for the full schema and per-principal variants.

SSO claims forwarding

creator_idp_claims forwards string-valued claims from your SSO provider (for example, Entra ID groups or preferred_username). To enable additional claims:
  1. Open Organization Settings → Login and Security in Ona.
  2. Add the scopes your IdP returns on login (for example, profile, email, groups).
  3. Configure your IdP to release those claims to Ona.
You can include any string-valued SSO claim in the sub using the creator_idp_claims.<key> syntax.

A note on the creator_ prefix

In Ona, environments have their own identity — they are machines, not users. The creator_ prefix makes explicit that those claims describe the user who created the environment, not the environment itself. The distinction matters when environments are launched by automations or shared across users.

V2 tokens

V2 tokens also work with Azure federated credentials. The V2 sub uses a path-based format (for example, org:<orgID>/prj:<projectID>/env:<envID>). Set the federated credential’s subject to the exact V2 sub value. V2 tokens carry fewer claims (org, gsub, and standard JWT fields), so trust is limited to matching sub. New integrations should use V3. See V2 tokens for the full V2 reference.

Troubleshooting

AADSTS70021: No matching federated identity record found
  • The sub claim in your Ona token does not match any federated credential’s subject.
  • Decode your token: ona idp token --audience api://AzureADTokenExchange --decode.
  • Compare it to the subject you registered. The match must be exact, including case.
  • Newly created federated credentials take a few minutes to propagate. Retry after the wait.
AADSTS700024: Client assertion is not within its valid time range
  • The token has expired. Ona OIDC tokens are short-lived. Re-run ona idp login azure.
AADSTS700016: Application not found in the directory
  • --client-id must be the client ID (appId) of the app registration or managed identity, not its object ID.
missing --client-id / missing --tenant-id
  • Pass the flags or set IDP_AZURE_CLIENT_ID / IDP_AZURE_TENANT_ID in the environment.

Further reading