[API Proposal] Make workload-identity federation reachable from a custom compute environment
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Background and Motivation
`Aspire.Hosting.Azure.Kubernetes` already implements workload-identity federation end to end — but
only on a path a custom compute environment cannot reach.
`AzureKubernetesEnvironmentExtensions.cs:835-862` emits the credential — and this is the **only**
occurrence of `FederatedIdentityCredential` anywhere in `src/`:
```csharp
foreach (var (resourceName, identityResource) in aksResource.WorkloadIdentities)
{
var existingIdentity = UserAssignedIdentity.FromExisting($"identity_{sanitizedName}");
existingIdentity.Name = identityNameParam;
infrastructure.Add(existingIdentity);
var fedCred = new FederatedIdentityCredential($"fedcred_{sanitizedName}")
{
Parent = existingIdentity,
Name = $"{resourceName}-fedcred",
IssuerUri = /* ...aks... oidcIssuerProfile.issuerURL */,
Subject = $"system:serviceaccount:{k8sNamespace}:{saName}",
Audiences = { "api://AzureADTokenExchange" }
};
infrastructure.Add(fedCred);
}
```
and the matching runtime wiring (annotated `ServiceAccountV1`, `podSpec.ServiceAccountName`, the
`azure.workload.identity/use` label) happens in the AKS environment's `prepare-aks-{name}` pipeline
step — registered at `AzureKubernetesEnvironmentResource.cs:47` and documented at `:35` as applying
"node-pool/workload-identity annotations to compute".
Two things lock this away from anyone else:
1. It runs only inside `ConfigureAksInfrastructure` (`AzureKubernetesEnvironmentExtensions.cs:510`),
a `private static` method wired exclusively as
`AzureKubernetesEnvironmentResource`'s infrastructure callback.
2. `aksResource.WorkloadIdentities` is `internal`
(`AzureKubernetesEnvironmentResource.cs:153` — `internal Dictionary`).
A compute environment that is not the built-in AKS one therefore never runs `prepare-aks`, and its
generated chart has **no ServiceAccount, no workload-identity pod label, and no federated
credential** — even though every type involved (`FederatedIdentityCredential`,
`KubernetesServiceCustomizationAnnotation`, `AppIdentityAnnotation`) is public.
### Is this the right ask? (division of responsibility)
Yes, with one deliberate boundary. The credential federates an identity **the AppHost declares**
to a service account **the AppHost's own chart creates** — both sides are the app's, so this is
app-model work, not platform work.
The boundary: federating a **platform-owned** identity (say, a shared cluster identity) is a
platform onboarding operation and is explicitly *not* what this asks for. We do not do that, and an
upstream API should not encourage it either.
We are also not asking Aspire to invent anything — only to make an existing, working emission
reachable.
## Proposed API
```diff
namespace Aspire.Hosting;
public static class AzureKubernetesEnvironmentExtensions
{
+ ///
+ /// Emits a federated identity credential linking to the
+ /// Kubernetes service account system:serviceaccount:{namespace}:{serviceAccount}.
+ ///
+ ///
+ /// The OIDC issuer is supplied as a value rather than read from a provisioned cluster, so this
+ /// works for a pre-existing cluster and for compute environments that provision no cluster.
+ ///
+ public static IResourceBuilder WithKubernetesServiceAccountFederation(
+ this IResourceBuilder identity,
+ BicepValue oidcIssuerUrl,
+ string kubernetesNamespace,
+ string serviceAccountName);
}
```
Taking `oidcIssuerUrl` **as a value** is the load-bearing detail: a custom compute environment
provisions no cluster template to read `oidcIssuerProfile.issuerURL` from.
## Usage Examples
```csharp
var identity = builder.AddAzureUserAssignedIdentity("workload-identity");
identity.WithKubernetesServiceAccountFederation(
oidcIssuerUrl: clusterIssuerUrl, // from a parameter or platform metadata
kubernetesNamespace: "my-namespace",
serviceAccountName: "my-workload");
```
The chart-side half (ServiceAccount + pod label) is already achievable today through the public
`KubernetesServiceCustomizationAnnotation`, so this one addition completes the scenario.
## Alternative Designs
- **Make `WorkloadIdentities` public and extract the emission into a public static helper.** Equally
good, and arguably tidier — it would let the AKS environment and third parties share one code
path rather than two.
- **Replicate it downstream.** What we do today; it is ~40 lines of stock `Azure.Provisioning`, but
it means the federation subject and the service-account name are owned in two different places
and can drift.
## Risks
Low — additive, and it emits the same stock `FederatedIdentityCredential` the AKS environment
already emits. The one judgement call is accepting the issuer as a value, which is strictly more
permissive than reading it from a provisioned cluster.
Contributor guide
Research direction
Start with AzureKubernetesEnvironmentExtensions.cs:510 and :835-862, then inspect AzureKubernetesEnvironmentResource.cs:35, :47, and :153 to understand the existing AKS-only path and internal workload-identity state. Compare the proposed identity extension with the public KubernetesServiceCustomizationAnnotation; done means the API design is agreed, custom compute environments can reach equivalent federation emission, and existing AKS behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, csharp, kubernetes
- Domain
- api, cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100