{"record":{"id":"ea90b0c6b6bbc831","repo":"hashicorp/terraform","slug":"retrieving-key-for-storage-account-q-s","errorCode":null,"errorMessage":"retrieving key for Storage Account %q: %s","messagePattern":"retrieving key for Storage Account %q: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/azure/api_client.go","lineNumber":184,"sourceCode":"\t\tlog.Printf(\"[DEBUG] Building the Blob Client from an Access Key\")\n\t\tauthorizer, err := auth.NewSharedKeyAuthorizer(c.storageAccountName, c.accessKey, auth.SharedKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"new shared key authorizer: %v\", err)\n\t\t}\n\t\tc.configureClient(blobsClient.Client, authorizer)\n\t\treturn blobsClient, nil\n\n\tcase c.azureAdStorageAuth != nil:\n\t\tlog.Printf(\"[DEBUG] Building the Blob Client from AAD auth\")\n\t\tc.configureClient(blobsClient.Client, c.azureAdStorageAuth)\n\t\treturn blobsClient, nil\n\n\tdefault:\n\t\t// Neither shared access key, sas token, or AAD Auth were specified so we have to call the management plane API to get the key.\n\t\tlog.Printf(\"[DEBUG] Building the Blob Client from an Access Key (key is listed using client credentials)\")\n\t\tkey, err := c.accountDetail.AccountKey(ctx, c.storageAccountsClient)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"retrieving key for Storage Account %q: %s\", c.storageAccountName, err)\n\t\t}\n\t\tauthorizer, err := auth.NewSharedKeyAuthorizer(c.storageAccountName, *key, auth.SharedKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"new shared key authorizer: %v\", err)\n\t\t}\n\t\tc.configureClient(blobsClient.Client, authorizer)\n\t\treturn blobsClient, nil\n\t}\n}\n\nfunc (c *Client) getContainersClient(ctx context.Context) (cc *containers.Client, err error) {\n\tif c.containersClient != nil {\n\t\treturn c.containersClient, nil\n\t}\n\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tc.containersClient = cc","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/azure/api_client.go#L166-L202","documentation":"When no explicit access_key, sas_token, or use_azuread_auth is configured, the Azure backend authenticates to the Azure Resource Manager (ARM) plane and calls StorageAccounts.ListKeys to fetch a storage account key, then uses that key to sign data-plane blob requests (getBlobClient default branch at api_client.go:182-184). This error wraps the failure of that ListKeys ARM call and surfaces the underlying ARM error (RBAC denial, account not found, throttling, etc.). It is thrown at the point the backend realizes it cannot obtain a key to talk to the storage data plane.","triggerScenarios":"Produced when getBlobClient reaches its default branch (no sasToken, no accessKey, no azureAdStorageAuth) and calls c.accountDetail.AccountKey -> storageaccounts.StorageAccountsClient.ListKeys, which returns an error. This happens on the first blob operation (state read/write) after Configure, because the key is fetched lazily.","commonSituations":"The Service Principal / Managed Identity / CLI credential used by Terraform lacks the 'Microsoft.Storage/storageAccounts/listKeys/action' permission or a Contributor-equivalent role on the storage account; a wrong subscription_id or storage_account_name typo; conditional-access policies blocking the ARM request; ARM throttling under many concurrent Terraform runs; the storage account is in a region/sovereign cloud the credential cannot reach.","solutions":["Grant the authenticated principal the 'Storage Account Contributor' role (or 'Storage Account Key Operator Service' role) scoped to the storage account or its resource group: az role assignment create --role 'Storage Account Key Operator Service' --assignee <principal-id> --scope <storage-account-resource-id>","Verify subscription_id and resource_group_name match the storage account: az storage account show -n <account> -g <rg> --query id","Switch to explicit access_key or use_azuread_auth = true in the backend block to bypass the ListKeys ARM call entirely","Confirm the credential can list keys directly: az storage account keys list -g <rg> -n <account>","For transient ARM throttling, reduce concurrent Terraform runs or retry after a short backoff"],"exampleFix":"// before (no auth method -> relies on ListKeys)\nterraform {\n  backend \"azurerm\" {\n    storage_account_name = \"mystorage\"\n    container_name       = \"tfstate\"\n    key                  = \"prod.terraform.tfstate\"\n    # no access_key / sas_token / use_azuread_auth\n  }\n}\n\n// after (avoid ListKeys entirely)\nterraform {\n  backend \"azurerm\" {\n    storage_account_name = \"mystage\"\n    container_name       = \"tfstate\"\n    key                  = \"prod.terraform.tfstate\"\n    use_azuread_auth     = true\n    subscription_id      = \"00000000-0000-0000-0000-000000000000\"\n    resource_group_name  = \"rg-tfstate\"\n  }\n}","handlingStrategy":"validation","validationCode":"# Before running terraform, confirm the principal can list storage keys\nACCOUNT_ID=$(az storage account show -n \"$ARM_STORAGE_ACCOUNT_NAME\" -g \"$ARM_RESOURCE_GROUP_NAME\" --query id -o tsv 2>/dev/null)\naz role assignment list --assignee \"$ARM_CLIENT_ID\" --scope \"$ACCOUNT_ID\" --query \"[].roleDefinitionName\" -o tsv | grep -iE 'Storage Account (Contributor|Key Operator)|Contributor' \\\n  || echo \"WARN: principal lacks listKeys permission -> error 140 likely\"\n# sanity: actually try to list keys\naz storage account keys list -g \"$ARM_RESOURCE_GROUP_NAME\" -n \"$ARM_STORAGE_ACCOUNT_NAME\" >/dev/null \\\n  && echo \"OK: ListKeys works\" || echo \"FAIL: ListKeys denied\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Grant the Terraform principal 'Storage Account Key Operator Service' or 'Contributor' scoped to the storage account, not the whole subscription","Prefer use_azuread_auth = true (data-plane RBAC) to remove the ListKeys dependency entirely","Pin subscription_id and resource_group_name in the backend block rather than relying on inference","In CI, assert 'az storage account keys list' succeeds as a pre-deploy gate"],"tags":["azure","authentication","storage","arm","rbac","shared-key"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}