Skip to content

AKS Platform: Identity and Access

This page describes who and what can access the platform and through which mechanism: human access, Kubernetes and Azure authorisation, workload identity, CI/CD identities, the Key Vault and break-glass access. The principle is no static credentials: everything uses Entra ID, managed identities or federated identities.

Reference design, your deployment may differ

Group and identity names are the patterns of the reference configuration. For the MCP-wide model see Identity and access model and Access, groups and PIM.

Principles

  • Humans get permissions through Entra ID groups only, never as individual assignments.
  • Production and non-production have separate groups. Production developer access is view-only by default.
  • Separation of duties: infrastructure deployment, image build and GitOps updates are separate identities.
  • Azure resource access is managed with Terraform. In-cluster authorisation is managed as YAML in the GitOps repository and changed by pull request.
  • Local Kubernetes accounts are disabled. Sign-in goes through Entra ID with MFA.

Identity types

Identity Authenticates through Authorised at Mechanism
Human users Entra ID (MFA) Kubernetes API Kubernetes RBAC bound to Entra ID groups
AKS cluster identity User-assigned managed identity Azure Resource Manager Azure RBAC (Cluster baseline)
Workload pods Service account to federated credential Azure services Workload identity and Azure RBAC
CI/CD pipelines GitHub OIDC federated credential Azure and Kubernetes Azure RBAC and cluster roles
Break-glass Entra ID with PIM, MFA Whole cluster cluster-admin binding

Groups

Group names follow grp-aks-<scope>-<role>[-<team>][-<env>]. The Terraform identity layer creates the groups listed in the entra_groups map of the configuration, plus the break-glass group.

Group Role Cluster
grp-aks-platform-admins Platform administrators, cluster-admin Both
grp-aks-platform-operators Manage ingress, monitoring and certificates Both
grp-aks-auditors Read-only, cluster-wide Both
grp-aks-breakglass Emergency access Both
grp-aks-<team>-leads-<env> Team leads Per environment
grp-aks-<team>-devs-<env> Team developers Per environment

The platform admin group and the break-glass group are passed to the cluster as its Entra ID admin groups. The hub-integrated configuration uses its own group set with an -integrated suffix, so the two clusters do not share groups.

Group membership and PIM activation are not configured in Terraform (limited provider support). The platform team or the customer's identity team manages them.

Kubernetes authorisation

Kubernetes RBAC is native (roles and bindings as manifests), deployed by GitOps. Azure RBAC for Kubernetes authorisation is switched on at the cluster, and the pipeline identities use the Azure role Azure Kubernetes Service RBAC Admin.

Role Kind Purpose
cluster-admin Built-in Platform admins and break-glass
platform-operator ClusterRole Manage platform namespaces: workloads, services, secrets, gateway and certificate resources, monitoring resources, network policies. View nodes and events
auditor ClusterRole Read-only across the cluster
namespace-admin Role Full management of a team namespace
namespace-developer Role Deploy and debug applications, including exec and routes
namespace-viewer Role Read and pod logs

Access matrix

Role dev test accp prod
Developer namespace-developer namespace-developer namespace-viewer namespace-viewer
Team lead namespace-admin namespace-admin namespace-admin namespace-developer
Platform operator View, cluster-wide View, cluster-wide View, cluster-wide View, cluster-wide
Auditor View, cluster-wide View, cluster-wide View, cluster-wide View, cluster-wide
Platform admin cluster-admin cluster-admin cluster-admin cluster-admin

Namespaces are named <team>-<env> (for example team-a-dev). The networking design document shows <env>-<team>; the RBAC manifests, the identity configuration and the load test all use <team>-<env>.

Protected platform namespaces

kube-system, gateway-system, cert-manager, monitoring, logging, argocd, policy-system and similar platform namespaces are protected: no role bindings for application teams, platform labels, admission policies that deny bindings by non-platform subjects, and GitOps-only changes in production. Labels use a configurable domain (<labelDomain>/type, <labelDomain>/protected, <labelDomain>/team, <labelDomain>/environment), set per customer in the GitOps repository.

Break-glass access

Aspect Design
Group grp-aks-breakglass, bound to cluster-admin
Members Two or three senior platform engineers at most
Activation PIM, time-limited, maximum 4 hours, MFA and justification required
Monitoring Alert on PIM activation and on Kubernetes audit activity of the group
Review Quarterly membership review

Workload identity

Each application gets its own user-assigned managed identity per environment, federated to one Kubernetes service account. Identities are not shared between applications, teams or environments.

sequenceDiagram
    participant Pod
    participant SA as Service account
    participant OIDC as AKS OIDC issuer
    participant Entra as Entra ID
    participant KV as Key Vault
    Pod->>SA: Runs as the annotated service account
    SA->>OIDC: Projected token
    OIDC->>Entra: Token exchange (federated credential)
    Entra-->>Pod: Azure token of the managed identity
    Pod->>KV: Read secret (Azure RBAC)

What Terraform creates for each entry of the workload_identities map:

Resource Name pattern Notes
Managed identity mi-<map key>-<env> In rg-<env>-identity
Federated credential fc-<env>-<namespace>-<service account> Issuer is the cluster's OIDC issuer, subject is system:serviceaccount:<namespace>:<service account>
Role assignments As listed per entry, for example Key Vault Secrets User on the Key Vault Least privilege per application
workload_identities = {
  "orders-api-prod" = {
    namespace            = "team-a-prod"
    service_account_name = "orders-api"
    roles = [
      {
        role_definition_name = "Key Vault Secrets User"
        scope                = "<key-vault-resource-id>"
      }
    ]
  }
}

Two steps on a new cluster

The workload identity module only runs when oidc_issuer_url is set, and the issuer URL exists only after the cluster has been created. On a new environment, deploy the cluster first, copy the issuer URL into the configuration, then apply again. On Azure Local the bootstrap script prints the URL.

CI/CD identities

Each entry in cicd_identities becomes a user-assigned managed identity mi-cicd-<name> with a federated credential fc-github-<name> for the GitHub OIDC issuer. The subject names a repository and a GitHub Environment, so only runs of that environment can use the identity. No client secrets exist.

Identity Responsibility Should not
infra-deploy Deploy infrastructure Push images, modify GitOps, deploy apps
image-build Build and push images Deploy infrastructure, read Key Vault, change the cluster
gitops-update (design) Update GitOps manifests Deploy infrastructure, push images, access Azure

Pipeline access to the cluster (for example for the load test) is granted as an Azure role assignment on the cluster (cicd_aks_role_assignments), kept outside the identity module on purpose. See Deployment.

Azure role assignments for people

The design gives the platform admins Azure Kubernetes Service Cluster Admin Role on the cluster, operators and auditors Cluster User Role, and the auditors Reader. In the code these are supplied through the identity_role_assignments map, which is empty or commented out in the reference files. Fill it in per environment.

Key Vault

Setting Value
Authorisation Azure RBAC, no access policies
Network Public network access disabled, default ACL action deny, private endpoint only (Azure variant)
Protection Purge protection on, soft delete 90 days (configurable)
SKU standard (can be premium for HSM-backed keys)
Name Globally unique, kv-<purpose>-<env> pattern, set in the configuration
Logging AuditEvent and policy evaluation logs to Log Analytics when a workspace is set

Workloads get only Key Vault Secrets User. The design chooses SDK-based access with workload identity over the CSI driver: each application uses its own identity, no secrets are copied into Kubernetes Secret objects, and the application controls caching. The CSI driver add-on is nevertheless switched on in the reference configuration files (see Cluster baseline). Rules for Kubernetes Secrets (no plaintext secrets in Git, prefer Key Vault, ownership labels) are in Security policy.

Audit

The design lists events to monitor and send to Log Analytics: Azure role assignment changes, managed identity and federated credential changes, break-glass activation, cluster-admin binding changes, failed Kubernetes sign-ins and service principal secret creation. Diagnostic settings are off by default in the reference configuration, so these need a Log Analytics workspace and the matching switches before go-live.