azure-aks-list-admin-cred

listClusterAdminCredential returns a static cluster-admin kubeconfig that bypasses AAD, giving unconditional cluster-admin access to the cluster.

derived azure emits CanReadCredential

match (effective permission)

{ "action": "Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action", "scope_type": "resource|resourceGroup|subscription" }

where

principal effectively holds the listClusterAdminCredential action at the cluster scope

emit

source typeIdentity
target typeCredential
source<principal>
target<cluster-admin kubeconfig (Credential) for the AKS cluster>
permissionsMicrosoft.ContainerService/managedClusters/listClusterAdminCredential/action
conditionsiam_permission service_state
state logicACTIVE when the cluster has localAccountsDisabled: false (default) — the returned client certificate is a fully valid static credential that requires no further Entra authentication. CONDITIONAL(deny_assignment) when localAccountsDisabled: true — the action still succeeds but returns an AAD-interactive kubeconfig, so the static-cert bypass does NOT apply; the cluster-admin cert path requires local accounts to be enabled. CONDITIONAL(service_state) if the cluster powerState.code is not Running. BLOCKED if a deny assignment covers this action at the cluster/RG/subscription scope.

Narrative

{principal.name} holds listClusterAdminCredential/action on cluster {target.name} and can retrieve a static client-certificate kubeconfig for cluster-admin, bypassing AAD authentication entirely - any further kubectl command runs with full cluster-admin privilege.

Raw rule rules/derived/azure/aks.yaml

id: azure-aks-list-admin-cred
emits: CanReadCredential
description: listClusterAdminCredential returns a static cluster-admin kubeconfig that bypasses AAD, giving
  unconditional cluster-admin access to the cluster.
match_effective_permission:
  action: Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action
  scope_type: resource|resourceGroup|subscription
where:
- principal effectively holds the listClusterAdminCredential action at the cluster scope
emit:
  source_type: Identity
  target_type: Credential
  source: <principal>
  target: <cluster-admin kubeconfig (Credential) for the AKS cluster>
  permissions:
  - Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action
  conditions:
  - iam_permission
  - service_state
  state_logic: "ACTIVE when the cluster has localAccountsDisabled: false (default) \u2014 the returned\
    \ client certificate is a fully valid static credential that requires no further Entra authentication.\
    \  CONDITIONAL(deny_assignment) when localAccountsDisabled: true \u2014 the action still succeeds\
    \ but returns an AAD-interactive kubeconfig, so the static-cert bypass does NOT apply; the cluster-admin\
    \ cert path requires local accounts to be enabled.  CONDITIONAL(service_state) if the cluster powerState.code\
    \ is not Running.  BLOCKED if a deny assignment covers this action at the cluster/RG/subscription\
    \ scope."
  confidence: 0.97
  false_positive_note: "When localAccountsDisabled: true (properties.disableLocalAccounts: true) the returned\
    \ kubeconfig is AAD-gated, NOT a static cert \u2014 do NOT emit ACTIVE for the static-cert bypass;\
    \ downgrade to CONDITIONAL(deny_assignment) with a note.  Verify the cluster is running (powerState.code\
    \ == Running) before emitting ACTIVE.  Deny assignments covering this action block it entirely."
  narrative: "{principal.name} holds listClusterAdminCredential/action on cluster {target.name} and can\
    \ retrieve a static client-certificate kubeconfig for cluster-admin, bypassing AAD authentication\
    \ entirely \u2014 any further kubectl command runs with full cluster-admin privilege."
move · open · esc close