Workload Identity Vending¶
Workloads need machine identities all the time: an app reading a database, a function writing to storage, a job calling an API. Sending each one through the platform team's Lane A process would make the platform a bottleneck. It also isn't necessary. Most workload identities can be managed identities that the workload's own pipeline creates, inside its own subscription, within guardrails.
- Platform Service Principal Vending: the short summary this page expands on.
- Key and Secret Management
Status: planned
Workload pipelines can create managed identities today, because they hold Contributor on their own subscription. The guardrails below are not yet in place: a constrained role-assignment identity, the approved role list, and enforced naming and tagging policy.
Lane A or Lane B?¶
| Lane A (a request to the platform team) if the identity needs any of these | Lane B (the workload pipeline) if it meets all of these |
|---|---|
| An Entra ID app registration or service principal | It is a managed identity (user-assigned or system-assigned) |
| Microsoft Graph permissions or Entra ID directory roles | It needs no Graph permissions and no directory roles |
| Azure roles at management group scope, or in another subscription | All its roles are within the workload's own subscription |
Privileged roles (Owner, User Access Administrator, RBAC Administrator) |
Its roles come from the approved list below |
Prefer system-assigned identities¶
| Type | Use when |
|---|---|
| System-assigned | One resource needs the identity. It is created and deleted with the resource, so it is never left behind. This is the default. |
| User-assigned | Several resources share it, it must exist before the resource does, or GitLab signs in with it through a federated credential |
Guardrails¶
1. A constrained role-assignment right¶
Creating a managed identity is easy. The risk is in what it is granted. The workload's role-assignment identity should hold Role Based Access Control Administrator on its own subscription, with a condition that limits:
- which roles it can assign, to the approved list only;
- which principal types it can assign to (
ServicePrincipal, which covers managed identities).
That way a compromised workload pipeline can't grant Owner, or give itself more rights than the list allows.
2. The approved role list¶
| Role | Typical use |
|---|---|
Reader |
Read-only monitoring or discovery |
Storage Blob Data Reader / Contributor |
Apps reading or writing blobs |
Key Vault Secrets User |
Apps reading secrets at runtime |
Azure Service Bus Data Sender / Receiver |
Messaging |
Monitoring Metrics Publisher |
Custom metrics |
AcrPull |
Pulling container images |
Add to the list by MR to the platform. Never add Owner, User Access Administrator, Role Based Access Control Administrator or Contributor.
3. Policy and detection¶
- Naming and tags on
Microsoft.ManagedIdentity/userAssignedIdentities, through the tagging standard. - Governance reporting (AzGovViz, the RBAC extract) flags any role assignment outside the approved list. See Governance Reporting.
- Federated credentials on user-assigned identities are limited to the workload's own GitLab project path.
Why this is safe in Lane B¶
The worst case of a compromised workload pipeline is limited to one subscription, and that pipeline already has Contributor there. A managed identity:
- is an Azure resource, not an Entra ID object, so creating one doesn't write to the directory;
- can't have a secret added to it, so the "add a credential and keep access" attack doesn't apply;
- can only be granted roles from the approved list, within the subscription.
That adds very little risk beyond what the pipeline already has, and removes a queue from the platform team.