Secure secrets with Azure Key Vault
What a vault holds, and the two planes you reach it through
A Python service that talks to PostgreSQL needs a password, and that password has to live somewhere. Put it in an environment variable and it is in your deployment template; put it in a settings file and it is in source control. Azure Key Vault's answer is to move the value into a managed store and leave behind only a URL such as https://contoso-kv.vault.azure.net, which is not itself a secret and can sit in a template in plain sight. Every other rule on this page follows from that one move, and from the question it forces: if the application holds no credential for the vault, what does the vault check before it hands the password over?
This page sits in the Secure, monitor, and troubleshoot Azure solutions domain, published by Microsoft at 20–25% of AI-200. Three sibling pages divide the rest of that domain, and the split is worth knowing before you read further: Azure App Configuration owns non-secret application settings, feature flags and its own store; distributed tracing and log queries own everything you inspect after the fact, including the vault's own diagnostic logs. This page owns Key Vault itself, which means the objects it stores, who is allowed to read them, how they rotate, and what happens when one is deleted.
Start with the container. Microsoft's authentication, requests and responses[1] reference names two container types under one resource provider. A vault is reached at <vault-name>.vault.azure.net and stores three kinds of thing, collectively called objects: cryptographic keys under /keys, secrets under /secrets, and certificates under /certificates. A Managed HSM is reached at <hsm-name>.managedhsm.azure.net and, per the object-type table in the keys, secrets and certificates overview[2], lists secrets and certificates as Not supported. It is a single-tenant, FIPS 140-3 Level 3 validated container for HSM-protected keys, not a higher-security drop-in for a vault. A workload whose job is to retrieve a password therefore still needs a vault no matter how strong its hardware requirement, because Managed HSM exposes no /secrets path to retrieve it from.
Within either container, every object has an object identifier, and its shape is worth memorising because three separate features depend on it:
https://<vault-name>.vault.azure.net/<object-type>/<object-name>/<object-version>
The version is a system-generated 32-character string. Microsoft calls an identifier that omits it a base identifier, and states plainly that you "can retrieve objects in Key Vault by specifying a version or by omitting the version to get the latest version of the object." Two names for one URL family, then: versioned pins one immutable version, versionless (the base identifier) follows whatever is current. Keep those two words; the rest of this page uses them for the SDK, for App Service references, and for customer-managed keys, and they mean the same thing in all three.
The last piece of vocabulary is the plane split, which the Azure RBAC guide[3] states directly. The control plane is "where you manage Key Vault itself": creating and deleting vaults, reading vault properties, changing access policies, all through management.azure.com. The data plane is "where you work with the data stored in a key vault": adding, deleting and modifying keys, secrets and certificates, through the vault's own hostname. Both authenticate through Microsoft Entra ID; they do not authorize the same way, and the next few sections are largely about that difference. The figure below shows the whole structure in one picture, from the resource provider down to the two identifier forms.
Reading a secret from Python, and the 401 that is supposed to happen
Retrieval is four lines, and Microsoft's Python quickstart[4] writes them like this:
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
client = SecretClient(vault_url="https://contoso-kv.vault.azure.net", credential=credential)
retrieved_secret = client.get_secret("pg-password")
print(retrieved_secret.value) # the plaintext
Every term in those lines is load-bearing. vault_url is the data-plane endpoint from the previous section, and because the DNS suffix differs by cloud (.vault.azure.net in the public cloud, .vault.azure.cn and .vault.usgovcloudapi.net in the sovereign clouds), it belongs in configuration rather than as a literal in code that has to run in more than one of them. credential is any object that can produce an access token; DefaultAzureCredential is one such object and the next section is entirely about which identity it ends up using. get_secret returns a KeyVaultSecret whose .value attribute is the plaintext string.
A SecretClient binds to exactly one vault. Reading from a second vault means a second client, and reading a key or a certificate from the same vault means a different client class entirely: KeyClient for /keys and CertificateClient for /certificates. The three object types are separate surfaces with separate operations and separate permissions, so the SDK gives each its own client rather than one client with a mode switch. That is the same three-way split the identifier suffixes showed, expressed in code.
The version argument is where the base-identifier rule reappears. The SecretClient reference[5] gives the signature as get_secret(name, version=None) and documents the parameter as "(optional) Version of the secret to get. If unspecified, gets the latest version." So client.get_secret("pg-password") is the base identifier expressed in Python, and it will silently start returning a rotated value. Passing a version string is the pin. Two neighbouring methods matter for the same reason: set_secret(name, value) "create[s] a new version of the secret" when the name is already in use rather than overwriting, and update_secret_properties(name, version=None, enabled=...) changes properties "but can't change the secret's value."
Now the part that wastes investigations. The very first call a Key Vault SDK client makes on a fresh process is expected to return HTTP 401, and it is not a symptom of anything. Microsoft's authentication reference states it as a note: "Key Vault SDK clients for secrets, certificates, and keys in the first call to Key Vault do not provide an access token to retrieve tenant information. It's expected to receive an HTTP 401 using Key Vault SDK client where the Key Vault shows to the application the WWW-Authenticate header containing the resource and the tenant where it needs to go and ask for the token. If everything is configured correctly, the second call from the application to Key Vault will contain a valid token and will succeed." The header carries two parameters: authorization, the address of the OAuth2 authorization service, and resource, the resource name to request a token for. This is challenge-based authentication, and it is how the client discovers which tenant to authenticate against without you configuring one. The figure below traces the full round trip.
The practical consequence is a diagnostic rule: a single 401 at the start of a process is the handshake. A 401 that persists after the retry is a real credential problem, and a 403 Forbidden is different again, meaning the token was accepted but the principal lacks the data action or is blocked by the vault firewall. Reading the first 401 as "DefaultAzureCredential failed" sends you looking for a broken identity that is working perfectly.
Which identity actually answers: the credential chain and the IMDS default
DefaultAzureCredential is not a credential. It is an ordered chain of credential types, and it returns the first token any of them can produce. The Python reference[6] lists the order: a service principal configured by environment variables, then WorkloadIdentityCredential if the workload identity webhook has set its variables, then an Azure managed identity, then the developer identities (a Windows shared token cache, Visual Studio Code, the Azure CLI, Azure PowerShell, the Azure Developer CLI) and finally brokered authentication. On a developer laptop the Azure CLI link usually wins; on an App Service or a container in Azure the managed-identity link wins first, so it never reaches the developer ones.
Three identity words get used interchangeably and should not be. A service principal is the directory object that represents an application rather than a person; Microsoft's authentication article describes its object ID as acting "like its username" and its client secret as acting "like its password." A managed identity is a service principal whose credential Azure creates, stores and rotates for you, which is why it is the recommended option: there is no client secret for anyone to leak. (The managed identities FAQ[7] adds a detail worth carrying: a managed identity has a service principal but no application object, so Microsoft Graph permissions must be granted directly to the service principal.) A credential chain is neither of those; it is the client-side selection logic that decides which of them to use.
That distinction is what resolves an apparent contradiction in the documentation. The quickstart says DefaultAzureCredential lets "your app use different authentication methods in different environments (local vs. production) without implementing environment-specific code", and the authentication article makes the same claim with different words. Read as a promise that nothing changes between environments, it is wrong, because the SDK reference documents a managed_identity_client_id keyword and an AZURE_CLIENT_ID environment variable that exist precisely to disambiguate. The accurate reading is narrower and still useful: the code is the same, the configuration is not. The line DefaultAzureCredential() never changes; which link of the chain fires, and which identity that link asks for, is decided by the environment around it.
So when do you have to intervene? The managed identities FAQ answers it in three cases, and they are the whole rule (the figure below lays them out):
- A system-assigned identity is enabled. "Azure Instance Metadata Service (IMDS) defaults to the system assigned managed identity." There is no failure here, and this is the case people most often get wrong: if the vault role was granted to a user-assigned identity and you name no client ID, the token comes back bound to the system-assigned one and the vault returns 403. The symptom is an authorization error, not an authentication error.
- No system-assigned identity, exactly one user-assigned. IMDS defaults to that single identity. The FAQ then warns that adding a second one later starts failing requests with
Multiple user assigned identities exist, please specify the clientId / resourceId of the identity in the token request, and recommends naming an identity explicitly even when only one exists today. - No system-assigned identity, two or more user-assigned. "[Y]ou're required to specify a managed identity in the request."
The operational advice collapses to one line: set AZURE_CLIENT_ID to the client ID of the identity you actually granted the role to, or pass managed_identity_client_id= to the credential. It costs nothing when there is only one identity and it is the difference between working and not when there are several.
Authorizing the vault: Azure RBAC or vault access policies
Authentication proves who is calling; authorization decides what they may do, and on the data plane a vault runs exactly one of two authorization models. The switch is the vault property enableRbacAuthorization, and the ARM reference states the exclusion without ambiguity: when it is true "the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored", and when false "the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored." There is no blended mode, and flipping the switch on a live vault is disruptive: the RBAC guide's own warning is that "[s]etting the Azure RBAC permission model invalidates all access policies permissions. It can cause outages when equivalent Azure roles aren't assigned."
| Consideration | Azure RBAC (recommended) | Vault access policies (legacy) |
|---|---|---|
| Where the grant lives | A role assignment in Azure Resource Manager | A list of principals in the vault's own properties |
| Scopes available | Management group, subscription, resource group, vault, or an individual secret, key or certificate | The whole vault only |
| Inheritance | A role assigned higher up applies downward | None; the vault's list is the whole story |
| How you grant read access to secrets | Assign Key Vault Secrets User | Grant the Get secrets permission |
| Default for a new vault | Yes, for vaults created with API version 2026-02-01 or later | Only if enableRbacAuthorization is set to false at creation |
Microsoft flags Azure RBAC as "(recommended)" on the secrets overview and access policies as "(legacy)", and as of API version 2026-02-01 the recommendation is also the default: "[w]hen you create a new vault with API version 2026-02-01 or later, the default access control model is Azure RBAC (enableRbacAuthorization = true)." That applies to create operations only. Existing vaults keep whatever they had, and a vault whose enableRbacAuthorization is null because it predates the property continues to use access policies. Both models remain fully supported, so "which model is this vault on?" is a real question to ask before debugging an access failure, not a formality.
On the RBAC side the two roles a developer meets are narrower than their names suggest, and the built-in role definitions[8] give the exact data actions:
- Key Vault Secrets User carries
Microsoft.KeyVault/vaults/secrets/getSecret/action("Gets the value of a secret") andMicrosoft.KeyVault/vaults/secrets/readMetadata/action("List or view the properties of a secret, but not its value"). Read only. It cannot create a secret and it cannot write a rotated version. - Key Vault Secrets Officer carries
Microsoft.KeyVault/vaults/secrets/*, which is every secret data action, described as "[p]erform any action on the secrets of a key vault, except manage permissions." A rotation function needs this one; the application that merely reads the result does not.
Two traps live in the gap between the planes. First, Key Vault Contributor is a control-plane role and grants no access to data; the RBAC guide says so in a note, and it is the most common over-grant on this objective. Second, and in the opposite direction, a principal with control-plane Contributor on an access-policy vault "can grant themselves access to the data plane by setting a Key Vault access policy", which is why Microsoft tells you to control that role tightly. Both roles look like they do the other one's job.
One further detail links this section to the eventing one below: changing the permission model is itself observable. The Event Grid schema lists Microsoft.KeyVault.VaultAccessPolicyChanged and notes that it "includes a scenario when Key Vault permission model is changed to/from Azure role-based access control", so an unexplained outage after a model flip is something you can alert on rather than discover from a support ticket.
exp, nbf and enabled: what actually stops a read
Set an expiration date on a leaked secret and you have not revoked it. This is the single most surprising behaviour on the whole objective, and the documentation states it directly enough that it is worth reading the source rather than a paraphrase.
A secret carries three lifecycle attributes. exp (expiration time) "sets the expiration time on or after which the secret data SHOULD NOT be retrieved, except in particular situations", and Microsoft adds that "[t]his field is for informational purposes only." nbf (not before) is the mirror image with the same informational caveat. enabled is the one with teeth: it "specifies whether the secret data can be retrieved", and when an operation falls between nbf and exp it "is only permitted if enabled is set to true."
That same enabled bullet then says something that reads like a flat contradiction of the informational caveat: "Operations outside the nbf and exp window are automatically disallowed, except in particular situations." Both sentences are on the same page, two bullets apart, and taken alone they cannot both be true. The reconciling clause is the one that appears in all three bullets and is easy to skim past: except in particular situations. The page names those situations in its own section, Date-time controlled operations, and for secrets there is no ambiguity left: "A secret's get operation works for not-yet-valid and expired secrets, outside the nbf / exp window. Calling a secret's get operation for a not-yet-valid secret can be used for test purposes. Retrieving (getting) an expired secret can be used for recovery operations."
So the two claims describe different scopes, and the safe formulation names the scope every time. For a get, expiry does not block retrieval; it is documented as an exception, deliberately, so an expired credential can still be recovered and a not-yet-valid one can still be tested. What exp genuinely buys you is not enforcement but signalling: it is the timestamp that drives the near-expiry event the rotation section relies on, and it is metadata a human or a policy can act on. Read as an access control, it is a false sense of security. Treat the general "automatically disallowed" statement as the rule for the object model at large, and the get exception as the documented, tested carve-out.
Revocation therefore has exactly one lever on this page. Disable the version:
client.update_secret_properties("pg-password", enabled=False)
A get against a disabled version fails, and it keeps failing until someone calls the same method with enabled=True. Note the argument shape from the SDK reference, update_secret_properties(name, version=None, ...): with no version it updates "the latest version", so disabling a compromised secret whose replacement has already been written is a two-step job, not a one-liner. And because the method "can't change the secret's value", disabling is a containment action, not a rotation. The next section is the rotation.
Rotation: three object types, three different answers to who makes the new value
"Autorotation" is one word covering three genuinely different mechanisms, and Microsoft's autorotation overview[9] separates them before describing any of them. Take the three in order, because picking the wrong one is a scenario question waiting to happen:
- Keys rotate. A cryptographic key can carry a key rotation policy, and "Key rotation generates a new key version of an existing key with new key material." Key Vault produces the material itself, on a schedule you set. Policy settings are an expiry time, a rotation time whose "minimum value is seven days from creation and seven days from expiration time", and a notification time for the near-expiry event. Managing the policy needs Key Vault Crypto Officer. The guidance to consuming services is the base-identifier rule again: "[t]arget services should use versionless key URI to automatically refresh to the latest version of the key."
- Certificates renew. Key Vault handles renewal itself, with an integrated certificate authority or by regenerating a self-signed certificate, on a configured percentage of lifetime or days before expiry.
- Secrets do neither on their own. Key Vault cannot invent a valid PostgreSQL password, because only PostgreSQL can decide what its own credential is. Secret rotation is therefore "[e]vent-based triggering via Event Grid" plus "[i]ntegration with Azure Functions for custom rotation logic": Key Vault tells you when, your code decides what.
Use the words that go with each. A key is rotated (new material generated by the vault), a certificate is renewed, and a secret's underlying credential is regenerated by the backing service before a new version is written. Saying "Key Vault rotates my database password" collapses all three and hides the fact that you have code to write.
The eventing half is a closed, published list. Key Vault emits ten event types whose names all begin Microsoft.KeyVault, three per object type plus one for the vault itself. For secrets those three are Microsoft.KeyVault.SecretNewVersionCreated, Microsoft.KeyVault.SecretNearExpiry and Microsoft.KeyVault.SecretExpired; the key and certificate trios mirror them, and Microsoft.KeyVault.VaultAccessPolicyChanged completes the set. Near-expiry fires on a fixed schedule the overview states as "30 days before expiration" (for keys, the rotation policy's notification time makes it configurable). Two constraints on that page are easy to miss and both cause silent no-ops: notification events "are triggered only on new versions of secrets, keys and certificates", and "you must first subscribe to the event on your key vault in order to receive these notifications." A vault nobody subscribed to emits nothing you will ever see. Handlers can be an Azure Function, a Logic App, or your own webhook.
Put together, the rotation loop is the four steps in Microsoft's rotation tutorial[10], traced in the figure below: near-expiry event, Event Grid delivery to the function, the function generates a new credential and writes it as a new secret version, the function updates the backing service. The tutorial is candid about the hazard in the middle: "There can be a lag between steps 3 and 4. During that window, the secret in Key Vault can't authenticate to [the backing service]." That gap is the argument for the two-credential pattern, where the service supports a second active credential and rotation alternates between them. Notice what the loop never does: it does not overwrite. The prior version stays addressable at its own versioned identifier, and any consumer holding the base identifier starts resolving the new one with no redeploy, which is the whole reason step three is a write rather than an edit.
Two timing numbers in that tutorial deserve a caveat rather than memorisation. It says "[i]f any step fails, Event Grid retries for two hours", while the Event Grid delivery documentation describes a default time-to-live of 1440 minutes across 30 attempts; and it says a short expiration date "publishes a SecretNearExpiry event within 15 minutes", where the two-credential tutorial says "within several minutes." Microsoft's own pages disagree on both, so neither number is safe to treat as a rule. What is stable, and what this page keys on, is the Key Vault side: which events exist, what triggers them, and that your handler owns the new credential. Event Grid's delivery guarantees, retry schedule and dead-lettering are taught on the Event Grid page, which owns that half of the contract.
Key Vault references: resolving a secret without writing code
There is a second way to get a secret into an application, and on App Service, Azure Functions and Logic Apps (Standard) it is usually the better one. Set an application setting or connection string to a Key Vault reference and the platform resolves it before your process starts, injecting the plain value as an ordinary setting. Microsoft's summary is four words long: "No code changes are required."
Keep the two paths named apart. A reference is @Microsoft.KeyVault(...), resolved by the platform with no SDK involved. A retrieval is SecretClient.get_secret, code you wrote and control. Both end with the value in your process; only one of them is something you can put a breakpoint in.
The reference documentation[11] gives two syntaxes, and the version rule is the base-identifier rule once more:
@Microsoft.KeyVault(SecretUri=https://contoso-kv.vault.azure.net/secrets/pg-password)
@Microsoft.KeyVault(VaultName=contoso-kv;SecretName=pg-password;SecretVersion=ec96f020...)
In the SecretUri form the version segment is optional; in the VaultName form SecretVersion is the optional part and VaultName and SecretName are required. Omit the version and "the app uses the latest version that exists in the key vault."
Resolution runs as an identity, and which one is a configuration decision: "Key vault references use the app's system-assigned identity by default, but you can specify a user-assigned identity" by setting the keyVaultReferenceIdentity property to that identity's resource ID. Note the blast radius stated one line later: "This setting applies to all Key Vault references for the app." It is an app-wide switch, not a per-setting one. Whichever identity resolves them needs read access on the vault, and the docs name the grant for both authorization models: assign Key Vault Secrets User under Azure RBAC, or the Get secrets permission under a vault access policy.
Rotation reaches a versionless reference on a schedule rather than instantly, and the numbers are worth holding: "[w]hen newer versions become available, such as with rotation, the app is automatically updated and begins using the latest version within 24 hours", because "App Service caches the values of the Key Vault references and refetches them every 24 hours." Two things shorten that. "Any configuration change to the app causes an app restart and an immediate refetch of all referenced secrets", and an authenticated POST to https://management.azure.com/[Resource ID]/config/configreferences/appsettings/refresh?api-version=2022-03-01 forces resolution on demand.
The failure mode is the part to commit to memory, because it is counter-intuitive and it is exactly what a well-built exam item probes. An unresolved reference does not leave the setting empty and does not stop the app from starting: "[i]f a reference isn't resolved properly, the reference string is used instead. Here's an example, @Microsoft.KeyVault(...)." Your code receives the literal reference text as though it were the password, and the first symptom is an authentication failure against the backing service with a nonsense credential, several layers away from the actual cause. Microsoft lists the usual causes as a misconfigured access policy, a secret that no longer exists, or a syntax error in the reference, and points at the portal's per-setting status dialog and the Key Vault Application Settings Diagnostics detector for the rest.
One boundary note. Configuring the identity on the function app, choosing a hosting plan, and everything else about how a function app is deployed belong to the function app configuration page. What this page owns is the other side of that contract: what the secret must be, which permission the identity needs on the vault, and what the platform does when the resolution fails.
Throughput: the throttle is the vault, and the fix is caching
Key Vault was built as a deployment-time store and is now routinely used at runtime, and Microsoft says as much: "Many applications and services use Key Vault similar to a database. However, the current service limits are not designed to support such high throughput scenarios." Design a service that calls get_secret on every request and you will meet HTTP 429 long before you meet anything else. When a threshold is crossed "Key Vault limits any further requests from that client, returns HTTP status code 429 (Too many requests), and the request fails."
The scope of that budget decides which fixes are available, so read the service limits[12] table header literally: transactions are counted per vault per region. Secrets and most other operations share a ceiling of 4,000 transactions per 10 seconds, while creating a secret, importing a certificate and importing a key share a much smaller 300 collectively. Key transactions are weighted rather than flat, and the reference works the arithmetic: because 4,096-bit HSM keys allow 250 GET transactions per 10 seconds against 2,000 for 2,048-bit, "it's eight times more expensive to use 4,096-bit keys compared to 2,048-bit keys because 2,000/250 = 8."
The footnote on that table is the constraint people plan around and then discover too late: "A subscription-wide limit for all transaction types is five times per key vault limit." Splitting traffic across vaults is a real lever, but only up to roughly five vaults' worth of throughput inside one subscription, after which the subscription ceiling binds and adding vaults buys nothing. The throttling guidance says the same thing from the operational side: "Do not send more than the subscription limit to the Key Vault service in a single Azure region."
Notice what the limits table does not have: a SKU or vault-size column for secret and vault transactions. There is no bigger-vault knob to reach for, and accordingly every lever the throttling guidance[13] offers is of a different shape. These are the ones to recognise in a scenario:
- Cache in memory. "Cache the secrets you retrieve from Azure Key Vault in memory, and reuse from memory whenever possible. Re-read from Azure Key Vault only when the cached copy stops working (for example, because it got rotated at the source)." A failed authentication against the backing service is the cache-invalidation signal, which is a neat inversion of the usual time-to-live approach and pairs exactly with the rotation model above.
- Divide across vaults and regions. The guidance's own worked example: "[i]f you have five apps, each in two regions, then we recommend 10 vaults each containing the secrets unique to app and region." One vault per security and availability domain.
- Fan out. Where many nodes need the same secret, have one entity read it and distribute to the rest, caching only in memory.
- Remove the secret entirely. "If you use Key Vault to store credentials for a service, check if that service supports Microsoft Entra authentication to authenticate directly." The fastest Key Vault call is the one you do not make.
- Back off exponentially, and never retry immediately. The documented client pattern is 1, 2, 4, 8 then 16 seconds. Immediate retries make it worse, because "[a]ll requests accrue against your usage limits" (the one relief is that "[f]ailed requests that return a 429 do not count towards the throttle limits").
One more piece of routing that follows from the limits table rather than from performance folklore: CREATE key and RELEASE key share a throttling category capped at 10 transactions per 10 seconds for HSM-protected keys, so for high-throughput secure key release Microsoft directs you to Managed HSM, which "provides dedicated HSM instances with higher limits." That is the one scenario where Managed HSM is the answer to a throughput question rather than a compliance one.
Deleting: soft-delete is retention, purge protection is prevention
The two delete-protection settings are constantly treated as one feature with a volume knob, and they are not. Soft-delete controls how long a deleted thing stays recoverable. Purge protection controls whether anyone can cut that window short. Getting the pair right is a design decision you make once at vault creation and cannot fully undo, so it is worth being precise.
Start with the shape of a deletion. Per the soft-delete overview[14], "[t]wo operations must be made to permanently delete a secret. First a user must delete the object, which puts it into the soft-deleted state. Second, a user must purge the object in the soft-deleted state." A soft-deleted object is not readable: it "can only be listed, recovered, or forcefully/permanently deleted." The second operation needs its own grant, the purge permission, available through the built-in Key Vault Purge Operator role. The states and the transitions between them are in the figure below.
Soft-delete is retention, and its parameters are fixed early:
- It is on by default. "When creating a new key vault, soft-delete is on by default. Once soft-delete is enabled on a key vault, it can't be disabled."
- Retention is "a configurable period of 7 to 90 calendar days", defaulting to 90. The ARM property
softDeleteRetentionInDays"accepts >=7 and <=90." - "The retention policy interval can only be configured during key vault creation and can't be changed afterwards." Deciding 7 days on day one and wanting 90 later means a new vault.
- The vault name is reserved for the whole window: "[y]ou can't reuse the name of a key vault that was soft-deleted, until the retention period expires." Re-running a deployment script against a name you just deleted fails, and the error is not obviously about soft-delete.
Purge protection is prevention, and it is a separate, opt-in commitment:
- "Purge protection is an optional Key Vault behavior and is not enabled by default. Purge protection can only be enabled once soft-delete is enabled."
- With it on, "a vault or an object in the deleted state can't be purged until the retention period passes." Not by an administrator, not by the subscription owner. The ARM reference puts it as "only the Key Vault service may initiate a hard, irrecoverable deletion."
- Enabling it is one-way: "Enabling this functionality is irreversible - that is, the property does not accept false as its value."
The security argument for the pair is the difference between them. Soft-delete on its own still permits an immediate purge, so an attacker or a bad script with the purge permission can destroy secrets in two calls and the retention window never protects anything. Purge protection is what converts retention into a guarantee, at the cost of an irreversible setting and a vault name you cannot recycle for up to 90 days. That trade is why Microsoft notes that "[m]ost Azure services that integrate with Azure Key Vault, such as Storage, require purge protection to prevent data loss" before they will use a vault for customer-managed keys.
One recovery caveat that catches teams mid-incident: recovering a soft-deleted vault does not put everything back. "When a Key Vault is soft-deleted, services that are integrated with the Key Vault are deleted. For example: Azure RBAC roles assignments and Event Grid subscriptions. Recovering a soft-deleted Key Vault does not restore these services. They must be recreated." So a recovered vault comes back with its secrets and without the role assignment your app reads them through, and without the event subscription your rotation function depends on. Plan the recovery as re-running your infrastructure deployment, not as flipping a switch.
Telling the scenarios apart
Scenario questions on this objective rarely ask what a feature does. They describe a symptom and ask which of four plausible mechanisms produced it, so the useful skill is a set of discriminators. These are the ones this page has earned, each pointing back at the section that establishes it.
A 401 versus a 403. A single 401 on a process's first vault call is the challenge handshake and needs no fix. A 401 that survives the retry is a token problem: no identity, wrong tenant, expired credential. A 403 means the token was fine and the principal was refused, which routes you to the authorization model, the role assignment, or the vault firewall, never to DefaultAzureCredential.
The app read a secret it should not have, or could not read one it should. Ask which identity the token was issued to before you touch the role assignment. With a system-assigned identity enabled and no AZURE_CLIENT_ID set, IMDS returns the system-assigned identity even when the vault role sits on a user-assigned one, and the result is a 403 that looks like a missing grant.
"We set an expiry and the old credential still works." That is documented behaviour for get, not a bug and not a propagation delay. Disabling the version is the only lever that stops a read.
"Rotation happened but the app kept using the old value." Three candidates, and the wording separates them. A versioned identifier or reference pins by design and will never move. A versionless App Service reference moves, but on a cache with a 24-hour refetch, so a restart or a configuration change is the fast path. Code that read the secret once at startup and held it forever is the third, and it is the one no platform setting fixes.
"The app is getting a nonsense password." If the workload uses Key Vault references, check whether the literal @Microsoft.KeyVault(...) string is being injected: an unresolved reference falls back to its own text rather than to an empty value, so the failure surfaces at the backing service.
429 under load. The budget is per vault per region, so the answers are caching, splitting across vaults and regions, and backing off. "Scale the vault up" is not an option that exists, and "add more vaults in the same subscription" stops helping once the subscription ceiling, five times a single vault's limit, is reached.
"The secret is gone and we need it back." Ask whether it was deleted or purged. Deleted means soft-deleted and recoverable within the retention window. Purged means gone, and if purge protection was on, purged is impossible before that window elapses. If a whole vault was recovered, the follow-up is that role assignments and Event Grid subscriptions came back missing.
"We need HSM-grade protection for a password." Managed HSM does not store secrets. The answer is a Premium vault, whose HSM-protected keys live alongside the secrets, not a Managed HSM instance.
Three ways a workload obtains a credential, and when each is the right answer
| Consideration | No secret (Microsoft Entra token to the service) | Key Vault reference (platform resolves it) | SDK retrieval (SecretClient.get_secret) |
|---|---|---|---|
| Who performs the exchange | Your SDK client for the target service, using its managed identity | The App Service or Functions platform, before your process starts | Your code, at whatever moment you call it |
| Where the value appears | Nowhere; there is no long-lived credential | As an ordinary app setting or environment variable | In a variable in your process memory |
| What the identity needs | A role on the target service, not on any vault | Key Vault Secrets User on the vault, or Get secrets under an access policy | The same vault permission as the reference path |
| How a rotation reaches it | Not applicable; tokens are short-lived and reissued | Version-less reference refetched within 24 hours, immediately on a config change or restart | On your next call, if you used the base identifier and did not cache indefinitely |
| How it fails | Token request fails, with the identity named in the error | Silently: the literal `@Microsoft.KeyVault(...)` string is injected as the value | A raised exception you can catch, retry, and log |
| Reach for it when | The service supports Microsoft Entra authentication at all | The secret is startup configuration on a platform that supports references | The host has no app-settings mechanism, or you need the value on demand |
Decision tree
Sharp facts the exam loves — give these one last read before exam day.
Cheat sheet
Sharp facts the exam loves — scan these before test day.
- SecretClient authenticated with DefaultAzureCredential retrieves a secret by name from a vault
Instantiate SecretClient(vault_url="https://.vault.azure.net", credential=DefaultAzureCredential()) and call get_secret(name) to read a secret at runtime; DefaultAzureCredential uses the app's managed identity in Azure and developer credentials locally, so no secret or connection string is embedded in code.
Trap Passing a raw API key or hard-coded credential to SecretClient defeats the purpose — the client is meant to be reached with a managed identity via DefaultAzureCredential.
11 questions test this
- Your team rotates a PostgreSQL password that is stored in Azure Key Vault, and each rotation adds a new version under the same secret name. A Python service in Azure Container Apps reads that password
- A Python service in Azure Container Apps authenticates to a partner API with mutual TLS, so it must hold a client certificate and its private key in memory. The certificate is stored in a key vault as
- A Python API on Azure Container Apps reads three secrets from a key vault during startup. After you turn on dependency tracing, every cold start records an HTTP 401 from the vault endpoint followed a
- A Python inference service on Azure Kubernetes Service reads a shared certificate password from a platform-wide key vault and its own model-registry token from a vault dedicated to that service, follo
- A Python API in Azure Container Apps reads several secrets from Azure Key Vault while handling a request. Support tickets show the API reporting 'secret not configured' for values that operators confi
- A Python service reads an API key from Azure Key Vault at startup by supplying only the secret name. During a support investigation you must be able to state exactly which secret version each running
- Your team ships one Python container image that runs both in a commercial Azure subscription and, for a government customer, in an Azure Government subscription. The image builds its SecretClient from
- A Python API on Azure App Service calls Azure Key Vault for the same downstream API key on every incoming request. Under peak load the vault starts returning HTTP 429 responses and request latency ris
- A Python worker caches a downstream service password that it read from Azure Key Vault by name when the process started. After the password is rotated in the vault, the worker keeps presenting the old
- A Python service that reads secrets from Azure Key Vault runs correctly on a developer workstation but fails on its first vault call after you deploy it to an Azure virtual machine. The failure is rai
- A Python inference service scales to dozens of replicas in Azure Kubernetes Service. Every replica reads the same three secrets from one key vault while it starts, and a large scale-out event now driv
- A versionless secret identifier returns the current version; a versioned identifier pins one exact version
A secret identifier without a version segment (.../secrets/), which Key Vault calls a base identifier, resolves to the latest version of the object, while appending a version (.../secrets//) pins that immutable version. get_secret with no version argument returns the latest version.
Trap Pinning a versioned URI means a rotated secret is NOT picked up; use the versionless identifier when you want rotation to flow through automatically.
6 questions test this
- Your team rotates a PostgreSQL password that is stored in Azure Key Vault, and each rotation adds a new version under the same secret name. A Python service in Azure Container Apps reads that password
- An incident review requires you to re-run last month's data-ingestion job exactly as it originally ran, using the same Azure Storage account key that the job used at the time. That key is held in Azur
- A Python service reads an API key from Azure Key Vault at startup by supplying only the secret name. During a support investigation you must be able to state exactly which secret version each running
- A partner API key held in a production key vault appears in a support transcript shared outside the company. Your incident lead has already stamped an expiration timestamp two hours in the past onto t
- An operations engineer stored a database connection string in a key vault with the wrong port number. A change ticket requires the vault to hold the corrected value under the same secret name, and req
- A Python worker caches a downstream service password that it read from Azure Key Vault by name when the process started. After the password is rotated in the vault, the worker keeps presenting the old
- Keys, secrets, and certificates each have a dedicated Key Vault client
The SDK exposes SecretClient for secrets, KeyClient for cryptographic keys, and CertificateClient for certificates; they are separate clients against the same vault endpoint because the three object types have distinct operations and permissions.
- Expiry and not-before are informational for a secret get; only enabled=false blocks retrieval
The exp and nbf attributes on a Key Vault secret are informational for a get - the docs carry a dedicated Date-time controlled operations section stating that a get works for not-yet-valid and expired secrets, so they can be used for test and recovery scenarios. Only enabled=false blocks a get. A get against a disabled version fails and the value cannot be read until the version is re-enabled with update_secret_properties(name, enabled=True).
Trap Setting an expiration date does not stop an application from reading the secret - code that must hard-stop access to a compromised credential has to DISABLE the secret version, not merely expire it.
3 questions test this
- Your team pre-stages next quarter's database credential as a new version in a production key vault six weeks before the cutover and sets that version's not-before attribute to the cutover date. Before
- A partner API key held in a production key vault appears in a support transcript shared outside the company. Your incident lead has already stamped an expiration timestamp two hours in the past onto t
- A Python worker on Azure Container Apps reads five secrets from one key vault at startup with a single client and a single identity. Four reads succeed and the fifth fails on every attempt, and the de
- A Key Vault SDK client's first call returns 401 by design - the challenge that discovers the tenant
Key Vault SDK clients for secrets, keys and certificates send their first request without an access token on purpose: Key Vault answers HTTP 401 with a WWW-Authenticate header naming the authorization endpoint and the resource, and the client then retries with a valid token. A 401 on a process's first Key Vault call is the expected handshake, not a misconfiguration; only a 401 that persists after the retry indicates a real credential or access problem.
Trap A 401 in traces or logs for the first Key Vault call does NOT mean DefaultAzureCredential failed - the handshake is how the client learns which tenant to authenticate against, so chasing it as a credential bug wastes the investigation.
- A SecretClient binds to one vault endpoint, and Managed HSM has no secrets surface at all
A SecretClient is constructed against exactly one vault's data-plane endpoint, and the DNS suffix is cloud-specific (.vault.azure.net in the public cloud, .vault.azure.cn and .vault.usgovcloudapi.net in the sovereign clouds), so the vault URL must be configuration rather than a literal in code that runs across clouds. Managed HSM is a keys-only container reached at .managedhsm.azure.net: it supports HSM-protected keys and nothing else, so secret retrieval has no Managed HSM equivalent.
Trap Managed HSM is not a higher-security drop-in for a vault that stores secrets - it exposes only /keys, so a workload that must RETRIEVE secrets still needs a key vault no matter how strong its HSM requirement is.
5 questions test this
- A release pipeline for an Azure Functions ingestion app needs the value of a storage connection string that is held in a key vault so it can run a post-deployment smoke test. An engineer added a step
- A Python service in Azure Container Apps authenticates to a partner API with mutual TLS, so it must hold a client certificate and its private key in memory. The certificate is stored in a key vault as
- A Python inference service on Azure Kubernetes Service reads a shared certificate password from a platform-wide key vault and its own model-registry token from a vault dedicated to that service, follo
- Your team ships one Python container image that runs both in a commercial Azure subscription and, for a government customer, in an Azure Government subscription. The image builds its SecretClient from
- A compliance review requires that your AI platform's cryptographic key material sit in single-tenant, FIPS 140-3 Level 3 validated hardware. A platform engineer proposes provisioning an Azure Key Vaul
- Key Vault throttles per vault per region, and the subscription ceiling is only five times one vault
Key Vault's transaction budget is enforced per vault per region and answers HTTP 429 once a client exceeds it, so a single high-traffic vault is the bottleneck rather than the subscription. Retrieval scales by caching secrets in memory and re-reading only when the cached copy stops working, and by splitting traffic across multiple vaults - but the subscription-wide ceiling is only five times a single vault's limit, so adding vaults inside one subscription stops helping.
Trap Retrying a 429 immediately does not help; and because the throttle scope is the vault resource, 'use a bigger vault' is not an available move - the levers are caching, more vaults, and eventually more subscriptions.
- Key Vault emits Event Grid events such as SecretNearExpiry and SecretNewVersionCreated to drive rotation
Key Vault publishes lifecycle events (Microsoft.KeyVault.SecretNearExpiry, SecretExpired, SecretNewVersionCreated) to Event Grid; subscribing an Azure Function to SecretNearExpiry lets you generate a new credential in the backing service and add it as a new secret version before the old one expires.
Trap Polling the vault on a timer to check expiry is the anti-pattern the event model replaces — rotation should be event-driven off SecretNearExpiry, not scheduled scanning.
14 questions test this
- An Event Grid-triggered rotation function regenerates the Azure Storage account key that your key vault holds as a secret. A mobile app uploads images into a blob container by using shared access sign
- An Event Grid-triggered function rotates an Azure Storage account access key that your key vault holds as a secret, regenerating the key at the storage account on each near-expiry event. A partner dow
- Your organization's rotation logic already runs in an HTTP-triggered Azure Function that is protected by a Microsoft Entra ID application, so it has to be registered on the Key Vault event subscriptio
- Your platform protects data with a customer-managed key that the security team imported into Azure Key Vault from its own on-premises hardware security module, and the key carries an expiration date.
- An Azure Key Vault secret exposes an Azure Storage account access key to a Python worker running on Azure Container Apps. You must rotate that access key from an Event Grid-triggered function, and the
- Three key vaults, one for production, one for test, and one that a partner manages, each hold a secret named apikey, and each vault has a near-expiry event subscription that delivers to the same rotat
- A rotation function subscribed to a key vault's near-expiry events replaced a database password once and has never run since, although the event subscription is healthy. Each rotation writes the new p
- You are wiring a new Python Azure Function that rotates database credentials to the near-expiry events of an Azure Key Vault. Event Grid must prove ownership of the endpoint without you writing any ha
- An Event Grid-triggered Azure Function rotates an Azure Storage account access key that your key vault holds as a secret. The function app's managed identity already reads and writes the vault's secre
- An API key that your key vault stores as a secret appeared in a support transcript that was shared outside the company, so the credential must be replaced immediately. The vault's near-expiry event fo
- A single Event Grid-triggered Azure Function rotates credentials for several different backing services. When a near-expiry event arrives, the function has to work out which resource to call, which of
- A shared Azure Function app rotates the credentials behind six secrets in one Azure Key Vault, and each secret is wired to the app through its own Event Grid event subscription. One backing service is
- A Python API on Azure Container Apps caches a database password in memory so that it does not call Azure Key Vault on every request. An Event Grid-driven function already rotates that password. You mu
- You develop a Python service on Azure Container Apps that calls a partner API with a key held as a secret in Azure Key Vault. The key must be replaced automatically before the stored secret reaches it
- Rotating a secret creates a new version, and versionless consumers pick it up automatically
Rotation does not overwrite in place; set_secret adds a new version and the prior version stays recoverable. Consumers that reference the secret by its versionless identifier begin resolving the new version automatically, which is what allows rotation without a redeploy.
Trap Thinking rotation overwrites the secret in place, so the previous value is gone.
6 questions test this
- An Event Grid-triggered function rotates an Azure Storage account access key that your key vault holds as a secret, regenerating the key at the storage account on each near-expiry event. A partner dow
- An Event Grid-triggered Azure Function has generated a replacement password in a backing database and now has to publish it to Azure Key Vault. Applications that read the secret without naming a versi
- An Azure Key Vault secret exposes an Azure Storage account access key to a Python worker running on Azure Container Apps. You must rotate that access key from an Event Grid-triggered function, and the
- A rotation function subscribed to a key vault's near-expiry events replaced a database password once and has never run since, although the event subscription is healthy. Each rotation writes the new p
- A rotation function subscribed to a key vault's near-expiry events wrote a malformed password into a secret, and a Python service that reads that secret without naming a version can no longer sign in
- A Python API on Azure Container Apps caches a database password in memory so that it does not call Azure Key Vault on every request. An Event Grid-driven function already rotates that password. You mu
- Cryptographic keys support a built-in automatic rotation policy
For keys (not secrets), Key Vault offers a rotation policy that regenerates the key on a defined interval and can fire a near-expiry Event Grid notification; secret rotation of external credentials still relies on a custom rotation handler.
- An app setting of the form @Microsoft.KeyVault(...) resolves a secret at runtime without code
Set an App Service or Functions application setting to @Microsoft.KeyVault(SecretUri=) (or @Microsoft.KeyVault(VaultName=...;SecretName=...)); the platform resolves it from Key Vault using the app's managed identity and injects the plain value as an environment variable, so the secret never appears in source control or configuration files.
Trap The app's managed identity still needs Get permission on the vault (Key Vault Secrets User under RBAC); without it the reference FAILS TO RESOLVE and the platform injects the literal '@Microsoft.KeyVault(...)' reference string as the setting value — it is never blank.
9 questions test this
- A Python Azure Functions app uses a Service Bus queue trigger. The queue connection string currently sits in a Key Vault reference application setting. A security review asks the team to eliminate the
- Your governance baseline requires every secret belonging to a function app to live in Azure Key Vault. The app's connection strings already resolve through Key Vault references. The remaining gap is t
- Your platform team keeps every credential in Azure Key Vault. An Azure Functions app already reads its connection string from an @Microsoft.KeyVault(...) application setting. A new Azure Container App
- Your Python function app in Azure reads SEARCH_KEY from an @Microsoft.KeyVault(...) application setting. Teammates must also run the same project on their laptops against a development search instance
- Your team runs a Linux Python function app on an Elastic Premium plan with regional virtual network integration. Its application settings are Key Vault references to a vault reachable only through a p
- Your team adds five Key Vault reference application settings to a Python App Service web app. Four resolve against the vault, but code reading the fifth receives the literal reference text. The app's
- You operate a Python Azure Functions app whose SEARCH_API_KEY application setting is a Key Vault reference. During a subscription cleanup, the role assignment that let the app read vault secrets was r
- You automate creation of an Elastic Premium function app with Bicep. To keep credentials out of the repository, you set the app's content share connection setting, WEBSITE_CONTENTAZUREFILECONNECTIONST
- You create a Python function app on an Elastic Premium plan from a single Bicep file that also creates the app's identity, its vault role assignment, and the Azure Files content-share settings whose c
- A versionless Key Vault reference automatically picks up a rotated secret; a versioned one pins it
When the reference omits the version, App Service periodically refreshes the resolved value (within about a day, or immediately on an application-settings change or restart) so a rotated secret flows in with no redeploy and no downtime; a versioned reference stays fixed to that version.
Trap Expecting a version-pinned Key Vault reference to follow a rotated secret.
2 questions test this
- Your team runs a Linux Python function app on an Elastic Premium plan with regional virtual network integration. Its application settings are Key Vault references to a vault reachable only through a p
- An on-call engineer rotates a compromised API key in Key Vault. A production Azure Functions app reads that key through a versionless Key Vault reference. Long-running queue processing must not be int
- Grant the workload's managed identity the Key Vault Secrets User role for read access
Assign the app's system- or user-assigned managed identity the data-plane role Key Vault Secrets User (get/list secrets) scoped to the vault; the app then authenticates with that identity via DefaultAzureCredential and reads secrets with no stored credential.
Trap Key Vault Secrets User grants only read (get/list); creating or rotating secrets requires Key Vault Secrets Officer — don't over- or under-grant the role.
11 questions test this
- You deploy a Python API to Azure Container Apps that reads a database password from an Azure key vault using the Azure role-based access control permission model. The app's managed identity must retri
- An Azure Functions admin job stores newly issued third-party API keys in the same Azure key vault that a Python service on Azure Container Apps reads them from. The vault uses the Azure RBAC permissio
- An audit of the subscription holding your AI services' key vaults lists many Key Vault Secrets User assignments whose principal is shown as Identity not found. They were left by function apps that wer
- Two product teams keep their application secrets in one shared Azure key vault that uses the Azure RBAC permission model. Each team's Python service must be able to read only its own secrets, and neit
- A developer runs your Python service on a workstation against a shared development Azure key vault that uses the Azure RBAC permission model. Deployed to Azure Container Apps the service reads its sec
- You move a Python service from Azure Container Apps to an AKS Standard cluster without changing its code, which builds a Key Vault client from DefaultAzureCredential. The user-assigned managed identit
- Your platform team authorizes every workload on its key vaults by creating Azure role assignments at the vault, and a deployment pipeline automates that step. The platform now adds an Azure Key Vault
- You are onboarding six Python Azure Functions apps to a single Azure key vault that uses the Azure RBAC permission model. Audit records must show which specific function app read a secret, and when an
- Two platform operators must be able to repair broken secrets in the key vaults that hold your Python AI services' credentials during an incident, which needs Key Vault Administrator across the resourc
- A production key vault still uses the vault access policy permission model. Your developers hold Contributor on its resource group so they can deploy. A security review finds that any of them can give
- A directory transfer moves the Azure subscription that holds your Python services and their key vaults from one Microsoft Entra tenant to another. The workloads' user-assigned managed identities have
- A vault uses either Azure RBAC or vault access policies, not both at once
Each vault's permission model is set by enableRbacAuthorization: Azure RBAC uses role assignments that inherit from subscription/resource-group scope, while the legacy vault-access-policy model assigns per-principal permissions on the vault itself. Microsoft recommends RBAC for consistent, scopeable management.
Trap Expecting a leftover vault access policy to still grant access once the vault moves to Azure RBAC.
10 questions test this
- An Azure Functions admin job stores newly issued third-party API keys in the same Azure key vault that a Python service on Azure Container Apps reads them from. The vault uses the Azure RBAC permissio
- An audit of the subscription holding your AI services' key vaults lists many Key Vault Secrets User assignments whose principal is shown as Identity not found. They were left by function apps that wer
- Your platform group must let an application team add and remove Key Vault data-plane role assignments on their own vaults so they can onboard new services themselves. The team must not be able to gran
- Two product teams keep their application secrets in one shared Azure key vault that uses the Azure RBAC permission model. Each team's Python service must be able to read only its own secrets, and neit
- A production Azure key vault still uses the legacy access policy model, and several Python services and a Functions app read secrets from it. Your team must move the vault to the Azure RBAC permission
- Your platform team authorizes every workload on its key vaults by creating Azure role assignments at the vault, and a deployment pipeline automates that step. The platform now adds an Azure Key Vault
- A platform team runs a shared Python diagnostics service that must read a health-probe secret from every key vault in a resource group, including vaults that other teams will create there later. The t
- Two platform operators must be able to repair broken secrets in the key vaults that hold your Python AI services' credentials during an incident, which needs Key Vault Administrator across the resourc
- A production key vault still uses the vault access policy permission model. Your developers hold Contributor on its resource group so they can deploy. A security review finds that any of them can give
- A directory transfer moves the Azure subscription that holds your Python services and their key vaults from one Microsoft Entra tenant to another. The workloads' user-assigned managed identities have
- DefaultAzureCredential chain and user-assigned identity client-id
DefaultAzureCredential tries an ordered chain of credentials - environment variables, then workload/managed identity, then developer credentials (Azure CLI / VS Code) - so the same SDK code authenticates locally and in Azure with no code change. Configuration is what differs: when the workload must authenticate as a USER-ASSIGNED managed identity, name it by client id (the AZURE_CLIENT_ID environment variable, or ManagedIdentityCredential(client_id=...)), because IMDS resolves an unnamed request to the system-assigned identity when one is enabled and rejects it outright when several user-assigned identities exist.
Trap Supplying no client id does NOT reliably fail: with a system-assigned identity enabled, IMDS defaults to it, so a role granted only to a user-assigned identity produces a 403 authorization error rather than an authentication error. The request fails outright only when no system-assigned identity is enabled and two or more user-assigned identities exist.
6 questions test this
- A developer runs your Python service on a workstation against a shared development Azure key vault that uses the Azure RBAC permission model. Deployed to Azure Container Apps the service reads its sec
- You move a Python service from Azure Container Apps to an AKS Standard cluster without changing its code, which builds a Key Vault client from DefaultAzureCredential. The user-assigned managed identit
- You are onboarding six Python Azure Functions apps to a single Azure key vault that uses the Azure RBAC permission model. Audit records must show which specific function app read a secret, and when an
- Your Python API runs in Azure Container Apps with one user-assigned managed identity, and developers also run the same code on their workstations, where they sign in with the Azure CLI. A standard req
- A Python API on Azure Container Apps reads secrets from a key vault with DefaultAzureCredential. In the staging environment every read fails, and the raised error carries one message for each credenti
- An Azure Container Apps app has a system-assigned managed identity and two user-assigned managed identities attached. Only one of the user-assigned identities holds the Key Vault Secrets User role on
- Soft-delete retains deleted vaults and secrets for a retention period so they can be recovered
Soft-delete (enabled by default and not disableable) keeps a deleted vault or secret in a recoverable state for its configured retention period; you recover the object during that window instead of losing it permanently.
Trap Assuming soft-delete can be switched off to make a delete immediate.
12 questions test this
- Your team already runs a Python retrieval service in one Azure region with its secrets in an Azure Key Vault, and is now standing up a second deployment of that service in another region. A compliance
- You operate an Azure Key Vault that stores API keys for a production AI workload, and soft delete is enabled on it. A threat-model review concludes that an attacker who takes over an administrative ac
- Your infrastructure pipeline tries to recover a production Azure Key Vault that was deleted by accident, but the deployment fails with a RequestDisallowedByPolicy error. The subscription carries a cus
- Your CI pipeline deploys a Bicep template that provisions an Azure Key Vault into a per-feature resource group, and a teardown job deletes that resource group when the branch merges. The pipeline reus
- Your Python housekeeping job runs nightly against your team's Azure Key Vault and must alert the on-call engineer while a mistakenly deleted secret can still be brought back, so it needs the moment at
- A colleague enabled purge protection on a shared Azure Key Vault that served a workload your team has now retired. The team deleted that vault yesterday, and a new project wants to provision a fresh v
- Your team's Python operations job uses the Azure Key Vault secrets client to bring back a credential that an engineer soft-deleted, and the same job run must then read that credential and hand it to a
- Your team keeps a wrapping key and several service credentials that cannot be regenerated from any other source in an Azure Key Vault with soft delete and purge protection enabled. An audit asks how t
- An engineer deletes a secret that holds a database password from your team's Azure Key Vault, and the Azure Function that reads it starts failing. The vault has soft delete and purge protection enable
- You develop a Python service on Azure Container Apps that reads credentials from Azure Key Vault. A decommissioned partner credential is stored as a secret, and a compliance ruling requires that value
- You provision an Azure Cosmos DB for NoSQL account that will hold your retrieval-augmented generation workload's embeddings under a customer-managed key. Your platform team already holds the RSA key i
- Your production Azure Key Vault was deleted by mistake and then recovered from the soft-deleted state well inside its retention period. The vault and every secret are back, but the Azure Function app
- Purge protection blocks permanent deletion until the retention period elapses
With purge protection enabled, a soft-deleted vault or secret cannot be purged (permanently deleted) before its retention period ends, defeating an attacker or accident that tries to erase secrets immediately. Purge protection cannot be turned off once enabled.
Trap Soft-delete alone still allows an immediate purge; only purge protection prevents early permanent deletion — the two settings are distinct.
10 questions test this
- Your team already runs a Python retrieval service in one Azure region with its secrets in an Azure Key Vault, and is now standing up a second deployment of that service in another region. A compliance
- You operate an Azure Key Vault that stores API keys for a production AI workload, and soft delete is enabled on it. A threat-model review concludes that an attacker who takes over an administrative ac
- Your CI pipeline deploys a Bicep template that provisions an Azure Key Vault into a per-feature resource group, and a teardown job deletes that resource group when the branch merges. The pipeline reus
- Your platform team needs a break-glass identity that can permanently remove soft-deleted Azure Key Vaults left behind by decommissioned AI workloads. Governance requires that the same identity must ne
- A colleague enabled purge protection on a shared Azure Key Vault that served a workload your team has now retired. The team deleted that vault yesterday, and a new project wants to provision a fresh v
- Your team keeps a wrapping key and several service credentials that cannot be regenerated from any other source in an Azure Key Vault with soft delete and purge protection enabled. An audit asks how t
- An engineer deletes a secret that holds a database password from your team's Azure Key Vault, and the Azure Function that reads it starts failing. The vault has soft delete and purge protection enable
- You develop a Python service on Azure Container Apps that reads credentials from Azure Key Vault. A decommissioned partner credential is stored as a secret, and a compliance ruling requires that value
- You provision an Azure Cosmos DB for NoSQL account that will hold your retrieval-augmented generation workload's embeddings under a customer-managed key. Your platform team already holds the RSA key i
- An audit finds that a departing administrator backed up the Azure Key Vault key that wraps your Azure Storage account's encryption key and restored that backup into another key vault. Purge protection
Also tested in
References
- Authentication, requests, and responses
- Azure Key Vault keys, secrets and certificates overview
- Provide access to Key Vault keys, certificates, and secrets with Azure RBAC
- Quickstart: Azure Key Vault secret client library for Python
- azure.keyvault.secrets.SecretClient class reference
- azure.identity.DefaultAzureCredential class reference
- Managed identities for Azure resources frequently asked questions FAQ
- Azure built-in roles for Security
- Understanding autorotation in Azure Key Vault
- Rotation tutorial for resources with one set of authentication credentials
- Use Key Vault references as app settings in Azure App Service
- Azure Key Vault service limits
- Azure Key Vault throttling guidance
- Azure Key Vault soft-delete overview