Entra Workload Identities

Set up Azure DevOps federation, register an organization identity, and grant deployment access across workspaces

Entra workload identities let your deployment pipeline authenticate to SteelEngine as an application. Configure the installation's trust, register the release application in its organization, then grant the actions the pipeline needs. Human SSO and SCIM are configured separately.

Preview. Qualify your actual Azure DevOps service connection, Key Vault access and deployment tasks before replacing an existing pipeline credential. Local signed-token and worker tests do not establish customer acceptance.

How Authentication Works

  1. Your Azure DevOps job uses its workload identity federation service connection to obtain a short-lived Entra access token for the SteelEngine resource API.
  2. The Python deployer or optional Node CLI sends that token as Authorization: Bearer <token> to /api/mcp/steelengine. /api/mcp/copilot remains a compatibility alias.
  3. SteelEngine validates the signature, expiry, configured tenant, API audience, required application role and app-only token type.
  4. SteelEngine matches the token's tenant, calling application ID and service principal object ID to an enabled organization identity. That identity's local grants decide which workspaces and operations it can use.
  5. Durable workflow execution carries an internal signed identity reference. The worker checks current trust and grants before preparing queued work. The external Entra token is not placed in the execution history.

A person does not create the pipeline's token in the dashboard. The dashboard approves the application and its permissions; Entra issues the token when the job authenticates. The Entra application role is an entry requirement. It does not assign a SteelEngine organization role or grant every action.

Before You Start

Use a compatible web, worker and migration release. Apply its complete migration chain, including 0297_workload_identities.sql and 0298_workload_organization_access.sql, before starting the new web and worker readers. Enable organizations and use an authenticated human administrator for dashboard setup.

Collect these identifiers from your identity team. None is a client secret or certificate private key:

ValueWhere It Is Used
Full token-issuing tenant GUIDInstallation trust; use the complete ID, not an abbreviated tenant prefix
SteelEngine resource API application client GUIDInstallation audience; identifies the API receiving the token
Resource API application ID URIToken scope, for example api://RESOURCE-API-CLIENT-GUID/.default
API application-role valueInstallation role, for example SteelEngine.Automation
Release application's client GUIDOrganization identity's Application (client) ID
Release application's service principal object GUIDOrganization identity's Service principal object ID, from Enterprise applications
Federated service connectionAzure DevOps job authentication and permission to use the connection

The resource API and the calling release application are separate registrations. The object ID on App registrations is also different from the service principal object ID under Enterprise applications.

1. Configure Entra and Azure DevOps

The identity team and pipeline owner configure the external connection:

  1. Register the SteelEngine resource API in the intended Entra tenant. Configure v2 access tokens and the idtyp optional access-token claim.
  2. Expose an application role such as SteelEngine.Automation that permits application members. Assign that API application permission to each approved release application and grant administrator consent.
  3. Create or select the Azure DevOps workload identity federation service connection for the release application. Use the issuer, subject and audience shown by that connection when configuring its federated credential in Entra. Copy those values exactly; their federation audience is distinct from the SteelEngine API audience.
  4. Authorize the intended pipeline to use the service connection. Give the identity only the separate Azure permissions needed for its tasks, including Key Vault secret-get access when applicable.

Use Microsoft's workload identity service connection setup, application-claim validation, and optional access-token claims references. Configure federation using the current connection's displayed values.

2. Configure Installation Trust

The installation operator controls which Entra authority and resource API SteelEngine accepts. You can install SteelEngine with workload authentication off and configure this later. These values are runtime configuration and do not require customer identifiers to be built into an image.

SettingInstallation EnvironmentOrganization Dashboard
Enable workload authenticationWORKLOAD_AUTH_ENABLEDOperator setup status is displayed
Trusted tenant, API audience, URI and required roleWORKLOAD_AUTH_PROFILETrust is displayed; it cannot be edited here
Approved release application and service principal—Register an identity in the organization
Workspace/workflow permissions and automatic access—Edit the identity's grants
Enable, verify or disable the identity—Enable/disable in the dashboard; verify from the pipeline

For Helm, add this to your installation values:

app:
  env:
    WORKLOAD_AUTH_ENABLED: "true"
    WORKLOAD_AUTH_PROFILE: '{"id":"company-automation","tenantId":"FULL-TENANT-GUID","audience":"RESOURCE-API-CLIENT-GUID","applicationIdUri":"api://RESOURCE-API-CLIENT-GUID","role":"SteelEngine.Automation"}'

The worker inherits both values from app.env unless you override them in worker.env. Keep web and all workers on the same trust configuration.

For the repository's Docker Compose stack, add the same settings to its .env:

WORKLOAD_AUTH_ENABLED=true
WORKLOAD_AUTH_PROFILE='{"id":"company-automation","tenantId":"FULL-TENANT-GUID","audience":"RESOURCE-API-CLIENT-GUID","applicationIdUri":"api://RESOURCE-API-CLIENT-GUID","role":"SteelEngine.Automation"}'

The Compose file forwards both values to web and the worker. Redeploy both processes after changing these settings. For a custom deployment, pass both environment values to each process explicitly.

Replace every GUID placeholder. The profile accepts exactly five fields: id, tenantId, audience, applicationIdUri and role. Its id is a local trust-profile name. audience is the resource API's client GUID; applicationIdUri is its URI, without /.default. The requested token scope appends /.default to that URI.

Permit the web process to reach login.microsoftonline.com over HTTPS for signing keys. SteelEngine derives issuer/key URLs from the configured tenant and caches/refreshes those public keys. It never stores an Entra client secret, certificate private key or access token as part of the identity registration.

Current Trust Limits

AreaSupported Behavior
TenantOne trusted workload tenant per installation, shared by its organizations; it can differ from the human SSO tenant
API audienceOne resource API audience per installation; many release applications can request tokens for it
Required Entra roleOne required application-role value; other token roles can also be present. Local SteelEngine grants remain per identity
Applications and organizationsMultiple identities are supported. Each service principal is bound to one organization per installation
CloudGlobal/commercial Entra at login.microsoftonline.com; sovereign-cloud authorities are not supported
Trust managementEnvironment configuration; multiple trust profiles and dashboard editing of installation trust are not implemented

Private AKS networking and self-hosted SteelEngine can use global Entra. This cloud limitation concerns the identity authority. Azure Government and Azure China use separate authorities.

The single-profile limit comes from this implementation's configuration model. Changing that model would require additional multi-profile support; moving the current fields to a dashboard alone would retain the limit. There is no old/new-profile overlap window. Trust changes make earlier verification stale and can reject queued work carrying the previous trust reference; already-admitted runs retain their admission.

3. Register the Organization Identity

Open Organization settings → Workload identities using a signed-in human with Manage organization workload identities permission. Organization administrators have this permission. API keys, workload tokens and anonymous disabled-auth sessions cannot manage these registrations.

  1. Select Add workload identity. Enter a readable release name, the release application's client GUID and its Enterprise applications service principal object GUID.
  2. Choose the workspace/workflow actions described below. You cannot delegate permissions beyond your own access.
  3. Save the identity. It starts disabled. Review its identifiers and access, then select Edit access → Enable application access when Entra is ready.
  4. Retain the binding ID and current configuration revision for pipeline verification. Saving or enabling does not mark the connection verified.
  5. Run the verification step from your pipeline. A successful workspace-read request records the current revision, trust configuration and verification time.

External identifiers and organization ownership are immutable. Register a new identity if they change. An edit increments the revision, and concurrent stale saves are rejected. Copy refreshed revision values after an edit.

Access Across Workspaces

Use explicit grants to select an existing workspace and, for supported workflow actions, optionally a specific workflow ID. A workflow grant without a workflow ID applies to that workspace's workflows.

For automatic access, an organization administrator selects actions under Automatic workspace access, or adds the capture, release, secrets or smoke preset. The selected actions apply to all active current and future workspaces in that organization. New workspaces need no repeated identity setup. SteelEngine resolves current membership at admission; it does not copy grant rows when a workspace is created.

Use Exclude workspaces for absolute exclusions. Remove conflicting explicit grants before saving. Clear workspace exclusions also removes exclusions for workspaces that are no longer listed. An empty automatic action list disables inheritance. Custom deny policies can require narrower explicit grants.

This policy grants only selected actions. Workload workspace creation and organization administration are outside the supported surface. Separate identities are needed for organizations sharing an installation. Separate installations configure their own trust and bindings.

Exact Actions and Minimum Grants

These are local SteelEngine permission keys. Entra issues a token for the API's application role using api://RESOURCE-API-CLIENT-GUID/.default; it does not issue one OAuth scope per row below.

Dashboard actionSteelEngine permissionMCP operations
Read workspace content.workspace:readsteelengine_workspaces.list/get, steelengine_tables.list
Read workflow folders.workspace:read_workflow_folderssteelengine_workflows.list_folders
Create workflow folders.workspace:create_workflow_folderssteelengine_workflows.create_folder
Read redacted workspace environment metadata.workspace:read_environmentsteelengine_env.list (names only)
Manage workspace environment variables.workspace:manage_environmentsteelengine_env.set
Create workflows.workflow:createsteelengine_workflows.create
Read workflow metadata.workflow:readsteelengine_workflows.list/get/export/check_deployment_status/list_deployment_versions
Update workflow drafts.workflow:updatesteelengine_workflows.import/update
Deploy workflows.workflow:deploysteelengine_workflows.deploy_api/redeploy/revert_to_version
Execute workflows.workflow:executesteelengine_workflows.run

tools/list advertises permitted tool groups; each invocation still checks its operation and target. There are four workload tool groups and nineteen supported operations. Confirmation is still required for protected mutations. Restore changes the definition; redeploy and check output to establish live rollback.

StageMinimum actions and scope
Capture sourceSource workspace read + workflow read; folder read only when enumerating folders. A workflow read grant may name one workflow.
Update existing targetTarget workspace read for the org guard; workflow update for import; deploy for deployment; read for lookup/status/versions. Scope workflow grants to its existing ID when possible.
Bootstrap target workflow/foldersAdd workflow create and folder create only when creating those resources; folder read when looking up bindings. The release preset includes these and update/deploy/read.
Inject secretsTarget workspace read for the guard + manage environment. Add read environment only if listing variable names. Azure Key Vault secret-get/RBAC remains separate.
Smoke runTarget workspace read for the guard + workflow execute, preferably a specific workflow ID. Referenced workflows can require additional execution grants.

Presets are conveniences and can be narrowed by unchecking actions. Use separate source/target identities and service connections when stages must have different authority. A single identity has the union of its grants in every job using that identity; stage names alone do not limit it.

4. Connect the Python Deployer

The Python reference client requires Python 3.10+ and Azure CLI. It runs inside AzureCLI@2 using the federated service connection. The Node CLI is optional.

Obtain the reviewed release's python_deployer.py and ado-python.yml, or use the repository copies under e2e/workload-identity/. The template's clientEntry parameter selects the Python file's path. For example, when the template and client are checked into your pipeline repository:

steps:
  - template: e2e/workload-identity/ado-python.yml
    parameters:
      serviceConnection: 'SteelEngine-QA-Release'
      clientEntry: 'e2e/workload-identity/python_deployer.py'
      origin: 'https://steelengine.example'
      scope: 'api://RESOURCE-API-CLIENT-GUID/.default'
      identity: 'DASHBOARD-BINDING-ID'
      revision: 2
      workspace: 'GRANTED-WORKSPACE-ID'
      organization: 'EXPECTED-ORGANIZATION-ID'

Replace the example revision with the current dashboard revision. Copy Workload identity ID and Organization ID from the identity details, and use the workspace ID from its verification command. The organization parameter is the internal ID, rather than a display name or slug. When consuming downloaded artifacts, set the template/client paths to their downloaded locations.

The client captures the output of az account get-access-token --scope 'api://RESOURCE-API-CLIENT-GUID/.default' --output json. Keep shell tracing off and do not print that response. Use the SteelEngine resource access token; ADO federation assertions and ARM/Key Vault tokens are different credentials.

The reference preflight sends a Bearer-authenticated POST to /api/automation/workload-identity/verify:

{"workspaceId":"GRANTED-WORKSPACE-ID","workloadIdentityId":"DASHBOARD-BINDING-ID","expectedRevision":2}

It then initializes MCP, sends notifications/initialized, lists tools and checks steelengine_workspaces.get → organizationId against the expected organization. Successful verification proves the selected workspace read; qualify the remaining operations separately.

Import SteelEngineClient into your existing Python deployer for subsequent calls. After creating a client with the installation origin/API scope and calling initialize():

client.call("steelengine_workflows", {
    "operation": "import", "workspaceId": target_workspace,
    "workflowId": existing_workflow, "json": exported_workflow, "confirm": True,
})

Use each operation's documented payload schema. The transport supports this server's 2025-03-26 and 2025-11-25 MCP versions and JSON/SSE responses. It refuses redirects, sanitizes failures and performs no automatic mutation retries. After an uncertain response, reconcile known workflow/deployment IDs before retrying.

See Azure CLI token acquisition and AzureCLI@2.

Optional Node Verification and Pilot

Install the reviewed SteelEngine CLI with Node.js 22 or later. In the Azure DevOps job, expose:

env:
  AZURE_TENANT_ID: $(deploymentTenantId)
  AZURE_CLIENT_ID: $(deploymentApplicationClientId)
  AZURE_SERVICE_CONNECTION_ID: $(deploymentServiceConnectionId)
  SYSTEM_ACCESSTOKEN: $(System.AccessToken)

AZURE_SERVICE_CONNECTION_ID is the ADO connection identifier, not the Entra service principal object ID. The CLI uses the agent's OIDC job environment through Microsoft's AzurePipelinesCredential. Run the command copied from the dashboard:

steelengine workload-identity verify \
  --base-url 'https://steelengine.example' \
  --scope 'api://RESOURCE-API-CLIENT-GUID/.default' \
  --identity 'DASHBOARD-BINDING-ID' \
  --workspace 'GRANTED-WORKSPACE-ID' \
  --revision 2

The optional workload-identity pilot --base-url ... --scope ... --manifest pilot.json exercises deterministic v1, v2 and restored/deployed-v1 workflow outputs in a disposable workspace. Its manifest contains identity/workspace/revision, expected organization, unique folder/workflow names, two workflow exports and expected outputs. Resources remain available for inspection and reconciliation. The repository's e2e/workload-identity/ado-pilot.yml runs it with the reviewed CLI and publishes its redacted report.

Key Vault, Renewal and Revocation

Key Vault requires its own resource token and Azure secret-get permission. Retrieve the secret from the agent and send its value directly to confirmed steelengine_env.set. Environment listing returns variable names only. Keep secret values out of logs, artifacts, workflow exports and reported outputs.

The Node pilot's optional keyVault manifest entry supplies vaultUrl, secretName, optional version and the SteelEngine variableName. It requests https://vault.azure.net/.default separately and supports public-cloud *.vault.azure.net vaults. See Key Vault Get Secret.

The Python transport requests an access token for each HTTP call; Azure CLI can return a valid cached token or acquire a fresh one. Qualify acquisition after expiry within your actual job lifetime. Reusing an unexpired cached token is not renewal evidence. Federation avoids storing a SteelEngine API key or release-application password for this path. Certificate-only authentication and certificate renewal are not enforced by this implementation.

Entra signing-key rotation is handled through refreshed public signing keys. Upstream application disablement can leave an already-issued token valid until expiry. Use the identity's local Disable action to block subsequent requests and queued worker preparation. Local grant/exclusion changes increment the revision; they require refreshed verification evidence but no replacement API key. Already-admitted execution and deployment compensation retain admission.

To disable the installation's workload path, set WORKLOAD_AUTH_ENABLED=false and redeploy web and all workers. Dashboard administrators can still inspect and disable identities.

Audit and Troubleshooting

Audited operations record the configured workload name snapshot, actorKind and stable workloadIdentityId; workflow ownership remains separate. Recent identity activity includes configuration changes and audited operations. Enterprise audit exports can filter by workload ID. Read/discovery requests are not a complete per-request access log.

SymptomCheck
Installation setup requiredBoth processes have workload auth enabled and a valid five-field profile; redeploy after editing environment values
401 / token rejectedToken is for the configured tenant/API, has v2 app-only claims, the required application role and a valid signature/expiry
403 / identity or access deniedExact application/service-principal binding, enabled state, correct organization, required local action, active workspace and exclusions
409 / verification or save conflictRefresh the identity revision; trust or configuration may have changed
Web accepts a request but queued execution is rejectedWorker trust/profile and build match web; the binding/revision/grant is still current before preparation
Verification succeeds but import/deploy/secret write failsWorkspace-read verification alone does not grant those actions; inspect operation grants and confirmation fields
New workspace inaccessibleEnable the appropriate automatic actions in its organization and check exclusions; the identity cannot create workspaces itself

Delivery Acceptance

Before replacing existing pipeline credentials, run the complete operation inventory with genuine Entra/ADO federation, separately authorized real Key Vault retrieval, denial after local revocation, new-workspace access and token acquisition after expiry. Restore an earlier definition, redeploy it and check observed output to establish rollback. Keep the exact installed image digests/build IDs and redacted ADO evidence.

Use separate source/target identities and service connections for environment access separation, and configure approvals in your release pipeline. These authentication and MCP operations support deployment automation; full workspace/connector/knowledge-base provisioning and an approval-driven cross-installation promotion system are separate capabilities.

On this page