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
- Your Azure DevOps job uses its workload identity federation service connection to obtain a short-lived Entra access token for the SteelEngine resource API.
- The Python deployer or optional Node CLI sends that token as
Authorization: Bearer <token>to/api/mcp/steelengine./api/mcp/copilotremains a compatibility alias. - SteelEngine validates the signature, expiry, configured tenant, API audience, required application role and app-only token type.
- 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.
- 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:
| Value | Where It Is Used |
|---|---|
| Full token-issuing tenant GUID | Installation trust; use the complete ID, not an abbreviated tenant prefix |
| SteelEngine resource API application client GUID | Installation audience; identifies the API receiving the token |
| Resource API application ID URI | Token scope, for example api://RESOURCE-API-CLIENT-GUID/.default |
| API application-role value | Installation role, for example SteelEngine.Automation |
| Release application's client GUID | Organization identity's Application (client) ID |
| Release application's service principal object GUID | Organization identity's Service principal object ID, from Enterprise applications |
| Federated service connection | Azure 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:
- Register the SteelEngine resource API in the intended Entra tenant. Configure v2 access tokens and the
idtypoptional access-token claim. - Expose an application role such as
SteelEngine.Automationthat permits application members. Assign that API application permission to each approved release application and grant administrator consent. - 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.
- 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.
| Setting | Installation Environment | Organization Dashboard |
|---|---|---|
| Enable workload authentication | WORKLOAD_AUTH_ENABLED | Operator setup status is displayed |
| Trusted tenant, API audience, URI and required role | WORKLOAD_AUTH_PROFILE | Trust 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
| Area | Supported Behavior |
|---|---|
| Tenant | One trusted workload tenant per installation, shared by its organizations; it can differ from the human SSO tenant |
| API audience | One resource API audience per installation; many release applications can request tokens for it |
| Required Entra role | One required application-role value; other token roles can also be present. Local SteelEngine grants remain per identity |
| Applications and organizations | Multiple identities are supported. Each service principal is bound to one organization per installation |
| Cloud | Global/commercial Entra at login.microsoftonline.com; sovereign-cloud authorities are not supported |
| Trust management | Environment 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.
- Select Add workload identity. Enter a readable release name, the release application's client GUID and its Enterprise applications service principal object GUID.
- Choose the workspace/workflow actions described below. You cannot delegate permissions beyond your own access.
- Save the identity. It starts disabled. Review its identifiers and access, then select Edit access → Enable application access when Entra is ready.
- Retain the binding ID and current configuration revision for pipeline verification. Saving or enabling does not mark the connection verified.
- 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 action | SteelEngine permission | MCP operations |
|---|---|---|
| Read workspace content. | workspace:read | steelengine_workspaces.list/get, steelengine_tables.list |
| Read workflow folders. | workspace:read_workflow_folders | steelengine_workflows.list_folders |
| Create workflow folders. | workspace:create_workflow_folders | steelengine_workflows.create_folder |
| Read redacted workspace environment metadata. | workspace:read_environment | steelengine_env.list (names only) |
| Manage workspace environment variables. | workspace:manage_environment | steelengine_env.set |
| Create workflows. | workflow:create | steelengine_workflows.create |
| Read workflow metadata. | workflow:read | steelengine_workflows.list/get/export/check_deployment_status/list_deployment_versions |
| Update workflow drafts. | workflow:update | steelengine_workflows.import/update |
| Deploy workflows. | workflow:deploy | steelengine_workflows.deploy_api/redeploy/revert_to_version |
| Execute workflows. | workflow:execute | steelengine_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.
| Stage | Minimum actions and scope |
|---|---|
| Capture source | Source workspace read + workflow read; folder read only when enumerating folders. A workflow read grant may name one workflow. |
| Update existing target | Target 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/folders | Add 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 secrets | Target workspace read for the guard + manage environment. Add read environment only if listing variable names. Azure Key Vault secret-get/RBAC remains separate. |
| Smoke run | Target 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 2The 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.
| Symptom | Check |
|---|---|
| Installation setup required | Both processes have workload auth enabled and a valid five-field profile; redeploy after editing environment values |
| 401 / token rejected | Token is for the configured tenant/API, has v2 app-only claims, the required application role and a valid signature/expiry |
| 403 / identity or access denied | Exact application/service-principal binding, enabled state, correct organization, required local action, active workspace and exclusions |
| 409 / verification or save conflict | Refresh the identity revision; trust or configuration may have changed |
| Web accepts a request but queued execution is rejected | Worker trust/profile and build match web; the binding/revision/grant is still current before preparation |
| Verification succeeds but import/deploy/secret write fails | Workspace-read verification alone does not grant those actions; inspect operation grants and confirmation fields |
| New workspace inaccessible | Enable 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.