Use a managed identity in code
Get a token for a workload's managed identity from inside its pod, with the .NET client or a plain HTTP call.
Code running in a workload's pod can get a short-lived access token for the workload's managed identity. The token lets the code call platform services as the workload, with the rights of the identity's roles — nothing more.
Important
Another workload's pods cannot get this token, but people can. Anyone who can run commands in the workload's pods (Kubernetes
pods/exec: Owner, Contributor, Apps Operator, Blueprints Operator, Platform Owner and Platform Contributor, assigned on the resource group or above) can read the pod's proof and fetch the token. Anyone who can create pods in the resource group's namespace (Owner, Contributor, Platform Owner, Platform Contributor, with direct cluster access) can get a token for any identity in the resource group. Giving an identity a role therefore gives it, in effect, to them as well — see How workload tokens are issued.
What the pod is given
| Variable | Value |
|---|---|
STACKSHIP_IDENTITY_RESOURCE_UID |
Which identity to ask for |
STACKSHIP_IDENTITY_TOKEN_ENDPOINT |
Where to ask, inside the cluster |
STACKSHIP_IDENTITY_POD_TOKEN_PATH |
The file holding the pod's proof of who it is |
Container instances are also given STACKSHIP_IDENTITY_PRINCIPAL_ID and
STACKSHIP_IDENTITY_CLIENT_ID when the instance's spec.identity records them.
Which containers get them:
| Workload | Containers |
|---|---|
| App | The app's container, in every slot |
| Function | The function's container; the identity is its function namespace's |
| Container instance | Every container and init container of a component that references a vault secret, or that asks for the identity with identityInjection: true in the API or a blueprint template. Other components get none |
The platform's secret-init container, which fetches vault secrets when a pod starts, gets them as well. The file-agent sidecar of a workload with a persistent volume gets none.
With .NET
The Stackship.Identity.Client package targets .NET 10. ManagedIdentityCredential reads the
variables above and fetches and caches tokens; DefaultStackshipCredential uses it when the
variables are present, and otherwise falls back to a service account's credentials from
STACKSHIP_CLIENT_ID, STACKSHIP_CLIENT_SECRET and STACKSHIP_TOKEN_ENDPOINT — handy on a
developer machine.
using Stackship.Identity.Client;
var credential = new DefaultStackshipCredential();
var token = await credential.GetTokenAsync();token.Token is the bearer token and token.ExpiresOn when it expires.
To put the token on every outgoing request, give an HttpClient the handler:
var http = new HttpClient(new StackshipTokenCredentialHandler(credential));services.AddDefaultStackshipCredential() registers the credential for dependency injection as
StackshipTokenCredential.
The Secrets client takes the same credential — see The .NET client.
With plain HTTP
Send a POST to the token endpoint with the identity's UID in the path and the pod's proof in
the header X-Stackship-Pod-Token:
curl -s -X POST \
-H "X-Stackship-Pod-Token: $(cat "$STACKSHIP_IDENTITY_POD_TOKEN_PATH")" \
"$STACKSHIP_IDENTITY_TOKEN_ENDPOINT/$STACKSHIP_IDENTITY_RESOURCE_UID/token"The answer is JSON with access_token, token_type (Bearer), expires_in in seconds,
client_id and principal_id. Ask again when the token expires, and read the proof file again
each time: it is replaced regularly.
When it answers 404
The endpoint answers 404 Not Found alike for every refusal — no such identity, no or an invalid
proof, a proof from another workload's pod, or a call from outside the cluster — so that it does
not reveal which identities exist. Check that the call runs inside the workload's own pod, that
the three variables are set, and that the proof file exists.
A token only proves who the workload is. What it may do comes from the identity's roles — see Give a managed identity a role.