Skip to content

fix(iac/azure): AKS workload identity is not wired up, so the UAI is unassumable by any pod #198

Closed

Description

@cristim

Surfaced during the adversarial review of LeanerCloud/cloud-commitments-cli#1817 (which closes LeanerCloud/cloud-commitments-cli#1621). Pre-existing; not introduced by that PR. Filed separately rather than widening LeanerCloud/cloud-commitments-cli#1817's scope.

What

terraform/modules/compute/azure/aks/ creates azurerm_user_assigned_identity.workload and, after LeanerCloud/cloud-commitments-cli#1817, grants it Key Vault Secrets User on the vault. But nothing in the module enables AAD Workload Identity, so no pod can obtain a token for that identity. Four pieces are required and three are missing:

piece location state
oidc_issuer_enabled = true azurerm_kubernetes_cluster.main (aks/main.tf:36-90) missing (defaults false)
workload_identity_enabled = true same resource missing (defaults false)
azurerm_federated_identity_credential binding the UAI to system:serviceaccount:<ns>:<project>-api anywhere missing (zero hits for azurerm_federated_identity_credential under terraform/)
azure.workload.identity/use = "true" label on the pod template aks/main.tf:244-249 missing
service-account annotation azure.workload.identity/client-id aks/main.tf:211 present

Without the OIDC issuer, the add-on, and a federated credential, the mutating webhook never injects AZURE_CLIENT_ID / AZURE_FEDERATED_TOKEN_FILE, and the service-account annotation alone does nothing.

Verified by enumeration on the LeanerCloud/cloud-commitments-cli#1817 branch: rg 'oidc_issuer_enabled|workload_identity_enabled|federated_identity|azure.workload.identity' terraform/modules/compute/azure/aks/ returns only the line-211 annotation, and rg -c 'azurerm_federated_identity_credential' terraform/ returns zero.

Why it matters

After LeanerCloud/cloud-commitments-cli#1817 the AKS workload identity has a correct RBAC grant on an identity it cannot assume. The grant model is right; the reachable failure is untouched. Nothing catches this: every individual resource is valid, terraform validate passes, and the LeanerCloud/cloud-commitments-cli#1817 guard only bans the wrong grant shape.

Not currently urgent. The AKS module is gated count = var.compute_platform == "aks" ? 1 : 0 and all three Azure environments select container-apps (github-{dev,staging,prod}.tfvars:18), so the module is not deployed anywhere today. This is a latent defect that would bite the first time someone selects compute_platform = "aks", which is exactly when they would least expect a secrets 403.

Fix direction

Add to azurerm_kubernetes_cluster.main:

oidc_issuer_enabled       = true
workload_identity_enabled = true

plus an azurerm_federated_identity_credential with subject = "system:serviceaccount:${namespace}:${project_name}-api" and audience = ["api://AzureADTokenExchange"], and the azure.workload.identity/use = "true" label on the pod template.

Verification bar

terraform validate will pass whether or not this works, so it proves nothing here. Either exercise a real cluster, or add a static assertion that the four pieces are present together, so that the presence of the UAI and its role assignment cannot again imply a working token path. Both directions: the assertion must fail when any one piece is removed, and pass on the complete wiring.

Activity

  1. cristim commented on Aug 13, 2026

    @cristim
    MemberAuthor

    Companion finding, now filed as #199: even once the workload identity is assumable, the AKS grant is read-only (Key Vault Secrets User) and the admin-password sync write path will still 403, so the database and Key Vault copies silently diverge.

    The two are sequential: fixing this issue alone leaves that write broken, and fixing #199 alone changes nothing observable until the identity here is assumable.

  2. IAmJSD commented on Oct 16, 2026

    @IAmJSD
    Collaborator

    Claiming: working on this

  3. self-assigned this
    on Oct 16, 2026
  4. added a commit that references this issue on Oct 17, 2026
    19fd9fc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions