hashicorp/terraform · error

retrieving key for Storage Account

Error message

retrieving key for Storage Account %q: %s

What it means

Thrown by getBlobClient in the default branch (no access_key, no sas, no aad) when c.accountDetail.AccountKey(ctx, storageAccountsClient) fails. AccountKey calls the ARM storageAccounts.ListKeys API and extracts a Full-permission key; failure means the ARM call failed (permissions, network, throttling) or no Full-permission key was returned.

Solutions

  1. Grant the principal Storage Account Contributor (or the narrower Storage Account Key Operator Service role) on the account.
  2. Switch to use_azuread_auth = true (recommended modern path) to avoid the key-list entirely.
  3. Provide access_key directly.
  4. Retry for transient ARM throttling; check Azure status for region incidents.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: verify the principal can list storage keys before configuring the backend.
// (Requires az login or an authenticated SDK client.)
func canListKeys(ctx context.Context, sub, rg, acct string) error {
    // use az CLI as the simplest check
    cmd := exec.CommandContext(ctx, "az", "storage", "account", "keys", "list", "-g", rg, "-n", acct, "--query", "[0].value", "-o", "tsv")
    out, err := cmd.Output()
    if err != nil { return fmt.Errorf("cannot list keys: %w (stderr: %s)", err, out) }
    if len(strings.TrimSpace(string(out))) == 0 { return fmt.Errorf("listed key was empty") }
    return nil
}

Try / catch

// If you must call getBlobClient directly, retry once on the list-keys failure (transient throttling).
var blob *blobs.Client
err := backoff.Retry(func() error {
    b, err := apiClient.GetBlobClient(ctx)
    if err != nil && strings.Contains(err.Error(), "retrieving key for Storage Account") {
        return err // retryable
    }
    if err != nil { return backoff.Permanent(err) }
    blob = b
    return nil
}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3))

Prevention

When it happens

Trigger: Default auth path (CLI/principal with no explicit data-plane creds). (a) The identity lacks Microsoft.Storage/storageAccounts/listKeys/action. (b) ListKeys returned keys but none has KeyPermission == Full. (c) ARM throttled or network failed.

Common situations: Service principal or managed identity with only Reader / Contributor-via-other-scope role; cross-tenant access where the principal cannot list keys; subscription throttling on busy accounts; key regeneration left the account in a transitional state.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/ea90b0c6b6bbc831. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/azure/api_client.go:184

		log.Printf("[DEBUG] Building the Blob Client from an Access Key")
		authorizer, err := auth.NewSharedKeyAuthorizer(c.storageAccountName, c.accessKey, auth.SharedKey)
		if err != nil {
			return nil, fmt.Errorf("new shared key authorizer: %v", err)
		}
		c.configureClient(blobsClient.Client, authorizer)
		return blobsClient, nil

	case c.azureAdStorageAuth != nil:
		log.Printf("[DEBUG] Building the Blob Client from AAD auth")
		c.configureClient(blobsClient.Client, c.azureAdStorageAuth)
		return blobsClient, nil

	default:
		// Neither shared access key, sas token, or AAD Auth were specified so we have to call the management plane API to get the key.
		log.Printf("[DEBUG] Building the Blob Client from an Access Key (key is listed using client credentials)")
		key, err := c.accountDetail.AccountKey(ctx, c.storageAccountsClient)
		if err != nil {
			return nil, fmt.Errorf("retrieving key for Storage Account %q: %s", c.storageAccountName, err)
		}
		authorizer, err := auth.NewSharedKeyAuthorizer(c.storageAccountName, *key, auth.SharedKey)
		if err != nil {
			return nil, fmt.Errorf("new shared key authorizer: %v", err)
		}
		c.configureClient(blobsClient.Client, authorizer)
		return blobsClient, nil
	}
}

func (c *Client) getContainersClient(ctx context.Context) (cc *containers.Client, err error) {
	if c.containersClient != nil {
		return c.containersClient, nil
	}

	defer func() {
		if err == nil {
			c.containersClient = cc

View on GitHub (pinned to d32a084675)