Theoretical Foundation: Manage access keys
1. Initial Intuitionβ
Think of a bank vault. You can give someone the right to access the vault in two different ways. The first: register them in the bank's system, linked to their identity, with specific permissions and a log of each access. The second: give them a copy of the physical key to the vault. With the physical key, they don't need to identify themselves in the system, there's no log linked to their identity, and if they lose the key or give a copy to someone, you don't know.
In Azure, access keys are exactly the "physical key to the vault". They are shared credentials that grant complete access to a service, without linked identity, without permission granularity, and without traceability of who did what.
The main service that uses access keys in the context of AZ-104 is the Azure Storage Account: every storage account has two access keys that, when presented, grant total control over all data and configurations in the account.
2. Contextβ
Access keys exist because, before the identity model based on Entra ID (RBAC and DataActions), it was the only way to authenticate programmatic access to Azure services. Applications needed credentials to access storage, and access keys were the initial solution.
Today, with evolved Entra ID, access keys are considered a legacy and less secure mechanism, but still widely present in real environments for compatibility and simplicity reasons.
Access keys are the starting point for understanding two other mechanisms: SAS tokens (Shared Access Signatures) and migration to identity-based authentication. For AZ-104, the focus is on understanding access keys, managing them securely, and knowing the rotation process.
3. Concept Constructionβ
3.1 What Are Storage Account Access Keysβ
Each Storage Account always has two access keys: key1 and key2. Both have exactly the same permission level: complete access to everything in the storage account, without exception.
The existence of two keys is not to have two access levels. It's to allow rotation without downtime: you can update your applications to use the new key before invalidating the old one, ensuring service continuity during the rotation process.
Each key is a long Base64 string, like:
dGhpcyBpcyBhIHN0b3JhZ2Uga2V5IGV4YW1wbGU=...
Anyone who has this string can perform any operation on the storage account: read, write, delete data, create containers, modify configurations, generate SAS tokens, everything.
3.2 Connection Stringsβ
A connection string is a string that encapsulates the storage account name and access key in a convenient format for application configuration:
DefaultEndpointsProtocol=https;AccountName=minhaconta;AccountKey=<access-key>;EndpointSuffix=core.windows.net
It's the equivalent of a URL + credential in a single string. Many applications and frameworks expect the connection string directly (Azure Functions, Azure Storage SDKs, etc.). An exposed connection string is equivalent to directly exposing the access key.
3.3 Shared Access Signatures (SAS)β
SAS tokens (Shared Access Signatures) are credentials derived from access keys, but with defined scope and term. They deserve attention because they are generated from access keys and their lifecycle is linked to them.
A SAS token has:
- Specific permissions: read-only, write-only, etc.
- Specific scope: only one container, only one blob, only queues
- Validity period: expires at a defined date and time
- IP restrictions (optional): can only be used from certain IPs
Critical point: when you rotate (regenerate) an access key, all SAS tokens generated from that key are immediately invalidated, even if they're still within the validity period. This is because the SAS is mathematically derived from the key; without the original key, it's invalid.
3.4 SAS Typesβ
There are three types of SAS, relevant for AZ-104:
| Type | Base | Characteristics | When to use |
|---|---|---|---|
| Account SAS | Access key | Scope: entire storage account or specific services (blob, file, queue, table) | Broad temporary access to multiple services |
| Service SAS | Access key | Scope: a specific service (e.g., blob only) with defined permissions | Temporary access to a specific service |
| User Delegation SAS | Entra ID credential | Doesn't use access key; uses Entra ID user identity to generate | Modern and recommended approach; doesn't depend on access keys |
The User Delegation SAS is important because it represents evolution: you can have the convenience of a SAS (scope, expiration) without depending on access keys. To generate a User Delegation SAS, the user needs the Storage Blob Data Contributor or Storage Blob Delegator role.
3.5 Access Key Access Controlβ
By default, any user with the Contributor or Owner role on a Storage Account can view the access keys. This is a risk: the control plane (RBAC) and data plane (access via key) are not completely separated by default.
Azure has a configuration called "Allow storage account key access" that, when disabled, prevents access keys from being used for authentication on the storage account. This forces the exclusive use of Entra ID-based authentication.
4. Structural Viewβ
5. Practical Operationβ
Access Keys Lifecycleβ
Rotation Process Without Downtimeβ
Access key rotation without service interruption follows a specific sequence that takes advantage of having two keys:
Why does this order matter? If you regenerate the key that applications are using without first migrating to the other one, all storage calls will fail immediately, as the applications' connection string or token contains the old key that is now invalid.
Important and Non-Obvious Behaviorsβ
Regenerating key1 invalidates all Account and Service SAS generated from key1. If you had active SAS tokens with 30-day validity generated from key1, they all become invalid instantly after regeneration. This can cause failures in systems using SAS without anyone noticing the connection.
The portal shows only the first letters of the key for security: when viewing access keys in the portal, you need to click "Show" to see the complete key. Each view is logged in the Activity Log, which is an important audit trail.
Automatic rotation via Key Vault: Azure Key Vault can store access keys and configure scheduled automatic rotation. When rotation occurs, Key Vault automatically regenerates the key in the storage account and updates the secret stored in Key Vault. Applications that fetch the key from Key Vault instead of having it embedded in code automatically receive the new version.
6. Implementation Methodsβ
6.1 Azure Portalβ
When to use: manual visualization, point-in-time rotation, emergency.
Path: Storage Account > Security + networking > Access keys
In this screen you can:
- See key1 and key2 (clicking "Show" to reveal)
- Copy the key or connection string
- Click "Rotate key" to regenerate key1 or key2
Advantages: immediate, no additional configuration, useful for incident response.
Limitations: manual, not scalable for multiple storage accounts, each view is logged individually.
6.2 Azure CLIβ
View access keys:
az storage account keys list \
--account-name minhaconta \
--resource-group rg-producao \
--output table
Regenerate key1:
az storage account keys renew \
--account-name minhaconta \
--resource-group rg-producao \
--key key1
Regenerate key2:
az storage account keys renew \
--account-name minhaconta \
--resource-group rg-producao \
--key key2
Get connection string (with embedded key):
az storage account show-connection-string \
--account-name minhaconta \
--resource-group rg-producao \
--output tsv
Advantages: scriptable, can be integrated into rotation pipelines.
Limitations: key is visible in terminal output and command history.
6.3 PowerShellβ
View access keys:
Get-AzStorageAccountKey `
-ResourceGroupName "rg-producao" `
-Name "minhaconta"
Regenerate key1:
New-AzStorageAccountKey `
-ResourceGroupName "rg-producao" `
-Name "minhaconta" `
-KeyName "key1"
Get connection string:
$key = (Get-AzStorageAccountKey `
-ResourceGroupName "rg-producao" `
-Name "minhaconta")[0].Value
$connectionString = "DefaultEndpointsProtocol=https;AccountName=minhaconta;AccountKey=$key;EndpointSuffix=core.windows.net"
6.4 Automatic Rotation via Azure Key Vaultβ
This is the safest and most recommended approach for production. Key Vault stores the access key as a secret and can configure automatic rotation:
Configure automatic rotation via CLI:
# Add key as secret in Key Vault
az keyvault secret set \
--vault-name meu-keyvault \
--name "storage-account-key1" \
--value $(az storage account keys list \
--account-name minhaconta \
--resource-group rg-producao \
--query "[0].value" -o tsv)
# Configure automatic rotation (via portal: Key Vault > Secrets > [secret] > Rotation policy)
The rotation policy defines:
- Rotation frequency (e.g., every 30, 60, 90 days)
- Notification X days before expiration
- Automatic action: generate new version and trigger event to webhook or Function App that executes rotation in storage
7. Control and Securityβ
Disable Access via Access Keysβ
To force exclusive use of Entra ID-based authentication and eliminate access key risk:
Via portal: Storage Account > Configuration > Allow storage account key access > Disabled
az storage account update \
--name minhaconta \
--resource-group rg-producao \
--allow-shared-key-access false
When disabled:
- Access keys still exist in the system, but cannot be used for authentication
- Connection strings based on access keys fail
- Account and Service SAS tokens fail (derived from keys)
- User Delegation SAS continues working (doesn't use access keys)
- RBAC DataActions continue working
Attention: before disabling, ensure that all applications accessing that storage are already using identity-based authentication (Managed Identity + RBAC DataActions). Otherwise, you'll break the applications.
Azure Policy to Audit and Block Key Usageβ
Azure has relevant built-in policies:
| Policy | Effect | What it does |
|---|---|---|
Storage accounts should prevent shared key access | Audit / Deny | Verifies if key access is enabled |
Configure storage accounts to disable shared key access | DeployIfNotExists | Automatically disables key access on new accounts |
These policies help ensure compliance across the organization.
Monitoring and Alertsβ
Activity Log: records all access key viewing and regeneration. Create an alert for when any key is regenerated:
az monitor activity-log alert create \
--name "alert-storage-key-rotated" \
--resource-group rg-monitoring \
--scopes "/subscriptions/<sub-id>" \
--condition category=Administrative and operationName=Microsoft.Storage/storageAccounts/regenerateKey/action \
--action-group "/subscriptions/<sub-id>/resourceGroups/rg-monitoring/providers/microsoft.insights/actionGroups/ag-security"
Microsoft Defender for Storage: detects suspicious patterns of access key usage, such as access from unusual geographical locations or abnormal operation volumes, and generates security alerts.
8. Decision Makingβ
Access Key vs. Identity vs. SAS: when to use each?β
| Situation | Recommended approach | Reason |
|---|---|---|
| Modern application in Azure (VM, Function App, Container) | Managed Identity + RBAC DataActions | No credential to manage, no leak risk |
| Legacy application that doesn't support Entra ID | Access Key via Key Vault (not embedded in code) | Compatibility maintained with added security |
| Temporary external partner access to a blob | User Delegation SAS | Limited scope, expires, doesn't expose key |
| Point-in-time data migration via AzCopy | Short-duration SAS token | Temporary and with defined scope |
| Local development environment | Access Key (temporarily) | Convenience, but never in production |
| Compliance requiring zero shared credentials | Disable key access + mandatory RBAC | Completely eliminates key risk |
When to rotate access keys?β
| Event | Action | Urgency |
|---|---|---|
| Key found in Git repository or log | Immediate rotation of exposed key | Critical: do now |
| Employee departure with key access | Preventive rotation | High: do same day |
| Periodic security routine | Scheduled rotation | Normal: monthly or per policy |
| Application migration to managed identity | Rotation after migration | After confirming app no longer uses key |
| Security audit detected suspicious access | Immediate rotation | Critical: do now |
9. Best Practicesβ
Never embed access keys directly in code: hardcoding credentials in code is one of the most common causes of leakage. Keys end up on GitHub, appear in logs, show up in tickets. Always store them in Key Vault or the application's configuration service (App Configuration, Function Apps App Settings).
Use Managed Identity whenever possible: for applications running in Azure, Managed Identity completely eliminates the need to manage access keys. The application obtains an Entra ID token automatically, with no credentials to store or rotate. Regular and automated rotation: even without incidents, rotate access keys regularly. Azure Key Vault with rotation policy fully automates this. 90 days is a common frequency; high-security environments may require 30 days.
Document which applications use each key: before rotating, you need to know what will be impacted. Maintain an updated inventory: "key1 of storage X is used by system Y and script Z". Without this inventory, a rotation can cause unexpected failures.
Disable key access in storage accounts that have already migrated to RBAC: once all applications of a storage account are using Managed Identity, disabling key access is an additional layer of protection. Even if someone obtains the key (for example, via unauthorized portal access), it cannot be used.
10. Common Errorsβ
Rotating the key that applications are using without migrating first to the other key
This is the most catastrophic error. The application was using key1, the administrator regenerates key1, the application's connection string points to the old key1 which is now invalid, and all storage operations fail immediately. The correct process is: migrate applications to key2, then regenerate key1; or migrate to new key1, then regenerate key2.
Invalidating SAS tokens when rotating key without considering who possesses them
An external system (partner, customer) received a SAS token valid for 30 days. The administrator rotates key1 from which the SAS was generated. The partner's SAS is instantly invalidated, even with 25 days of remaining validity. This causes failure in the partner's system without prior notice. Before rotating a key, check if there are active SAS tokens derived from it and plan the transition.
Exposing the connection string in environment variables insecurely
In many environments, the storage connection string is placed in server environment variables or in .env files. If these files remain in the Git repository, or if server logs record environment variables, the connection string (and therefore the access key) leaks. The correct approach is to reference the key via Key Vault, never store it directly in plain text environment variables in production.
Confusing key regeneration with revoking access to a specific user
Access keys are not linked to a user. Regenerating key1 revokes access from anyone who was using key1, including legitimate systems. If the goal was to revoke access from a specific user, the correct approach would be to revoke that user's RBAC assignment, not regenerate a key that affects everyone.
Not monitoring access key views
Each time someone clicks "Show" to view an access key in the portal, this is logged in the Activity Log. Many organizations don't monitor these events. An internal attacker collecting credentials can view keys from multiple storage accounts without any alert. Configure alerts for access key views.
11. Operation and Maintenanceβ
Access Key Usage Auditβ
To verify if a storage account is having its keys used (instead of RBAC):
# Check current configuration
az storage account show \
--name minhaconta \
--resource-group rg-producao \
--query "allowSharedKeyAccess" \
--output tsv
To audit all storage accounts in the subscription that still allow key access:
az storage account list \
--query "[?allowSharedKeyAccess!=false].{Nome:name, RG:resourceGroup, KeyAccess:allowSharedKeyAccess}" \
--output table
Check Last Key Rotationβ
Unfortunately, Azure doesn't directly expose the date of each key's last rotation via CLI in a simple way. The best source is the Activity Log:
az monitor activity-log list \
--resource-group rg-producao \
--start-time $(date -d '90 days ago' +%Y-%m-%dT%H:%M:%S) \
--query "[?operationName.value=='Microsoft.Storage/storageAccounts/regenerateKey/action'].{Data:eventTimestamp, Conta:resourceId, Operador:caller}" \
--output table
Important Limitsβ
| Item | Detail |
|---|---|
| Keys per storage account | Always exactly 2 (key1 and key2) |
| Maximum number of derived SAS | No documented limit |
| Maximum duration of an Account SAS | 7 days (service security limitation) |
| Maximum duration of a User Delegation SAS | 7 days (delegation key maximum term) |
| Activity Log retention | 90 days default |
12. Integration and Automationβ
Complete Automatic Rotation with Azure Functions + Key Vault + Event Gridβ
The most robust pattern for key rotation automation is:
This pattern completely eliminates manual rotation. Key Vault triggers the event, the Function executes the rotation process in safe sequence, and applications that fetch the key from Key Vault automatically receive the new version without interruption.
Gradual Migration to Managed Identityβ
For organizations wanting to eliminate access key usage progressively:
- Enable Managed Identity in the application (VM, Function App, etc.)
- Assign
Storage Blob Data Contributorrole (or appropriate role) to the Managed Identity on the storage account - Update the application to use Azure SDK with DefaultAzureCredential (which automatically uses Managed Identity)
- Test and validate access via identity
- Remove the access key from application configuration
- After confirming no application uses the key anymore, disable
allowSharedKeyAccesson the storage account
13. Final Summaryβ
Essential points:
- Access keys are shared credentials that grant complete and unrestricted access to a Storage Account. There's no permission granularity, no linked identity.
- Each Storage Account always has exactly two keys (key1 and key2), both with the same access level. Two keys exist to allow rotation without downtime.
- Rotating a key instantly invalidates all SAS tokens (Account SAS and Service SAS) derived from that key, even if they're still within validity period.
- Connection strings encapsulate account name + access key. Exposing the connection string is equivalent to exposing the access key.
- The Allow shared key access setting can be disabled to force exclusive use of Entra ID-based authentication.
Critical differences:
- Account SAS and Service SAS are derived from access keys and are invalidated when the key is rotated. User Delegation SAS is derived from an Entra ID credential and is not affected by access key rotation.
- Access Key vs. Managed Identity + RBAC: the key is a shared secret without identity; Managed Identity is authentication without credential, with permission granularity via DataActions.
- Key rotation vs. user access revocation: rotating a key affects everyone who was using it, not a specific user. To revoke a user's access, use RBAC (remove the role assignment).
What needs to be remembered:
- Never embed access keys in code. Always use Key Vault for secure storage.
- Follow the correct rotation sequence: migrate to the alternate key before regenerating the key in use.
- Before rotating, identify all SAS tokens derived from the key that will be invalidated.
- Configure alerts in Activity Log for key regeneration and key views.
- The long-term goal is to eliminate access key usage in favor of Managed Identity + RBAC DataActions, and disable
allowSharedKeyAccessin migrated storage accounts. - Access keys don't exist only in Storage; other services like Azure Cosmos DB, Azure Cache for Redis, and Azure Service Bus also use similar access key mechanisms. The management pattern and risks are the same.