The Default: No Alerts At All

By default, Azure Key Vault doesn’t notify you when a secret is about to expire. It will happily let a certificate reach its expiry date and take down your production TLS endpoint without sending a single email.

This catches a lot of teams off guard. Key Vault stores the expiry date, displays it in the portal, and does absolutely nothing with it unless you configure alerting yourself.

Here are the three main approaches, from simplest to most complete.

Option 1: Azure Policy (Compliance Flagging)

Azure Policy can flag secrets, keys, and certificates that expire within a certain number of days. It doesn’t send alerts, but it lists non-compliant items in the Azure Policy compliance dashboard.

You don’t need to write the policy yourself. Microsoft ships built-in definitions for this:

  • Secrets should have more than the specified number of days before expiration
  • Keys should have more than the specified number of days before expiration
  • [Preview]: Certificates shouldn’t expire within the specified number of days

Assign them at the subscription or management group level. For example, the secrets policy with a 30-day threshold:

az policy assignment create \
  --name secrets-expiring-30d \
  --policy b0eb591a-5e70-4534-a8bf-04b9c489584a \
  --scope "/subscriptions/{sub}" \
  --params '{"minimumDaysBeforeExpiration": {"value": 30}}'

If you do write a custom definition, it must use the Microsoft.KeyVault.Data mode and the Microsoft.KeyVault.Data/vaults/secrets type. The control-plane type Microsoft.KeyVault/vaults/secrets won’t match anything inside the vault. Microsoft also suggests assigning the certificate policy several times at different thresholds, such as 180, 90, 60 and 30 days.

Pros: Easy to set up. Works across all vaults in scope. No custom code. Cons: Not real-time. Microsoft says results for existing items can take up to two hours to appear. You have to check the compliance dashboard yourself, and nothing is pushed to you.

Option 2: Event Grid + Logic App (Real-time Alerts)

Key Vault emits events through Azure Event Grid when secrets, keys, or certificates approach expiry. This is the most common approach for real alerting.

Events available

Event When it fires
Microsoft.KeyVault.SecretNearExpiry 30 days before expiry
Microsoft.KeyVault.SecretExpired On expiry date
Microsoft.KeyVault.KeyNearExpiry Set by the key’s rotation policy
Microsoft.KeyVault.KeyExpired On expiry date
Microsoft.KeyVault.CertificateNearExpiry 30 days before expiry
Microsoft.KeyVault.CertificateExpired On expiry date

According to Microsoft’s event reference, the secret and certificate “NearExpiry” events fire 30 days before expiry, and that can’t be changed. For keys, the timing is configurable through the key’s rotation policy.

Setting up the Event Grid subscription

# Create an Event Grid subscription that sends to a Logic App
az eventgrid event-subscription create \
  --name secret-expiry-alerts \
  --source-resource-id "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/my-vault" \
  --endpoint "LOGIC_APP_TRIGGER_URL" \
  --included-event-types \
    Microsoft.KeyVault.SecretNearExpiry \
    Microsoft.KeyVault.SecretExpired \
    Microsoft.KeyVault.CertificateNearExpiry \
    Microsoft.KeyVault.CertificateExpired

The Logic App

Create a Logic App with an HTTP trigger that receives the Event Grid event and sends an email or Teams message. The event payload includes:

{
  "subject": "my-secret",
  "eventType": "Microsoft.KeyVault.SecretNearExpiry",
  "data": {
    "Id": "https://my-vault.vault.azure.net/secrets/my-secret/abc123",
    "VaultName": "my-vault",
    "ObjectType": "Secret",
    "ObjectName": "my-secret",
    "Version": "abc123",
    "NBF": null,
    "EXP": 1735689600
  }
}

Parse the EXP field (Unix timestamp) to include the actual expiry date in your notification.

Pros: Real-time. Push notifications to email, Teams, Slack, whatever your Logic App targets. Cons: Requires setup per vault. The 30-day threshold is fixed for secrets and certificates. Logic Apps have their own cost.

Option 3: Azure Monitor Log Alerts

Key Vault writes a log entry every time it publishes a near-expiry or expired event, whether or not anything subscribes to it. If you send the vault’s logs to Log Analytics, you can alert on those entries with a query.

Enable diagnostic logging

az monitor diagnostic-settings create \
  --name kv-diagnostics \
  --resource "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/my-vault" \
  --workspace "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/my-workspace" \
  --logs '[{"category":"AuditEvent","enabled":true}]'

Create a log alert rule

The operation names come from Microsoft’s Key Vault logging reference. This query returns every near-expiry and expired notification:

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName in (
    "SecretNearExpiryEventGridNotification", "SecretExpiredEventGridNotification",
    "CertificateNearExpiryEventGridNotification", "CertificateExpiredEventGridNotification",
    "KeyNearExpiryEventGridNotification", "KeyExpiredEventGridNotification")
| sort by TimeGenerated desc

Save it as a log alert rule that fires when the result count is greater than zero, and point it at an action group (email, Teams, ITSM). One rule can cover every vault that sends logs to the same workspace.

Pros: One alert rule for many vaults. Works with existing alert infrastructure (action groups, ITSM connectors). Cons: Depends on diagnostic logs being enabled on every vault. Same fixed 30-day timing as Event Grid for secrets and certificates. Log ingestion costs.

The Blind Spots

The push options depend on per-vault setup. Event Grid needs a subscription on every vault, and the log query only sees vaults that send their logs to your workspace. With 30 Key Vaults across 8 subscriptions, one missed setting is a blind spot. The built-in policy Deploy - Configure diagnostic settings for Key Vaults to Log Analytics workspace closes part of that gap by adding the log setting to new vaults automatically.

There are other blind spots too:

App Registration credentials aren’t in Key Vault. Event Grid doesn’t fire NearExpiry events for App Registration client secrets or certificates. Those live in Entra ID, not Key Vault, and have no built-in alerting at all.

Certificates served outside Key Vault aren’t covered either. A certificate uploaded straight to an App Service, an Application Gateway listener or API Management was never in a vault, so no Key Vault event fires for it, however close it gets to expiry.

The 30-day threshold may not be enough. For secrets that require coordination across multiple teams for rotation, 30 days is tight. You might want alerts at 90, 60, and 30 days.

No dependency context. An alert that says “secret X in vault Y is expiring” is useful, but you also need to know which applications consume that secret. Otherwise you’re scrambling to trace the dependency at alert time instead of having that context ready.

Putting It All Together

For most teams, we recommend this layered approach:

  1. Azure Policy at the management group level for baseline compliance visibility
  2. Event Grid + Logic App on production Key Vaults for real-time push notifications
  3. Regular discovery scans to catch App Registration credentials and any vaults missing Event Grid subscriptions

If you want all of this without the per-vault configuration burden, CertifyClouds scans every Key Vault and App Registration across all your subscriptions, along with the certificates your App Services, Application Gateways, API Management, Container Apps and Front Door serve, alerts at whatever thresholds you set (90, 30 and 7 days, for example), and maps which resources use each secret so you know what breaks before it expires.


Further Reading