Skip to content
Stackship documentation Svenska

Managed identitiesAdministrators

How workload tokens are issued

Where managed identities live, how a pod proves which workload it is, and what the token endpoint refuses.

Where identities live

The Managed Identity service keeps no database. Each identity is a confidential client in the platform's identity provider, named mi- followed by the resource's ID, with service-account tokens enabled and nothing else. The client's description records the resource's type, name, resource group and boundary, and that record is where the service reads an identity's placement from. The identity's principal ID is the client's service-account user.

The resource's ID is its Kubernetes UID for apps and function namespaces, and an ID derived from the boundary, resource group and name for container instances.

The token endpoint

Pods fetch tokens from the service inside the cluster:

text
POST http://module-managedidentity.stackship-system:8080/api/identities/<resource-uid>/token

The operator puts this address into workload pods as STACKSHIP_IDENTITY_TOKEN_ENDPOINT, taken from its setting ManagedIdentity__TokenEndpoint. The installer sets that to the platform's namespace. Without it the operator falls back to http://module-managedidentity.stackship-system.svc.cluster.local:8080/api/identities, which is right only for a platform in stackship-system. Setting ManagedIdentity__Enabled to false stops the variables for apps and functions; container instances get them regardless, whenever a component needs the identity.

The endpoint is not published through the platform API, and it refuses callers whose address is not a private or cluster-internal one.

How a pod proves who it is

A pod has no platform credential when it asks — that is the point of the endpoint — so the resource UID in the path is only an address, not a secret. The proof is a Kubernetes service-account token that the operator has the kubelet project into the pod:

  • at /var/run/secrets/stackship.se/identity/token, named by STACKSHIP_IDENTITY_POD_TOKEN_PATH;
  • minted for the audience stackship-managed-identity: followed by that resource's UID, and valid for ten minutes;
  • mounted into every container that is told which identity to use.

The pod sends it in the header X-Stackship-Pod-Token. The service has the platform's kernel review it with the Kubernetes API server of the cluster the workload runs on, for the audience of the identity being asked for — so a pod's token only ever passes for its own resource's identity — and then requires the pod's namespace to be the namespace of the identity's resource group.

Important

The audience binding keeps one workload's pod from using its proof for another workload. It does not keep out people who hold rights in the resource group's namespace:

  • Anyone who can run commands in the workload's pods — Kubernetes pods/exec, which Owner, Contributor, Apps Operator, Blueprints Operator, Platform Owner and Platform Contributor carry when assigned on the resource group or above — can read the proof file and fetch the identity's tokens.
  • Anyone who can create pods in the namespace — Owner, Contributor, Platform Owner and Platform Contributor, with direct cluster access — can have a token minted for any stackship-managed-identity:<uid> audience, and so obtain any identity in that resource group.

Treat those rights as equal to holding the roles of every identity in the resource group.

Only then does the service obtain an access token from the identity provider and return it. The identity's client secret never leaves the service on this path.

What is refused

Every refusal is the same 404: no such identity, no proof, a proof that does not pass review, a pod in another namespace, a caller from outside the cluster. The service's log says which. When the kernel cannot be reached, the endpoint refuses rather than hands out identities, so workloads with secrets do not start until it is back.

Creating and deleting identities

The platform creates an identity when an app, function namespace or container instance is created, and deletes it when the resource is deleted; the operator also creates a missing one for an app or function namespace it reconciles, and one for each S3 storage account. Creating is idempotent: an identity that already exists for the resource is reused. The identity is given no role.