Key Vault and Secrets
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. See the section bibliography for the reference material consulted while preparing these pages. |
Commands on this page are current for Azure CLI 2.90.0 (checked 2026-09-27); re-verify against az version and
the linked reference pages before relying on them in a pipeline. Key Vault control-plane behaviour is also
version-sensitive in a way most other services on this site are not: API version 2026-02-01 changed the
default access-control model for newly created vaults to Azure RBAC, and every control-plane API version
before 2026-02-01 retires on 2027-02-27 — both re-verified below against the official migration guidance.
Every Bookshelf service that touches a database connection string, an API key, or a TLS certificate reads it
from kv-bookshelf rather than an environment variable or a config file: catalog-api and orders-api read
secrets directly with the SDK, notifier (and any App Service/Functions equivalent) resolves a Key Vault
reference, and workloads on aks-bookshelf mount secrets through the Secrets Store CSI driver. This page covers
the vault itself — what it stores, how access is controlled, its safety nets, and its network posture — and
then each of those consumption paths in turn.
Objects: secrets, keys, and certificates
A single Azure Key Vault stores three kinds of object, each versioned, each addressable by a data-plane URI of
the form https://kv-bookshelf.vault.azure.net/\{secrets,keys,certificates\}/<name>/<version>:
- Secrets
-
Opaque name/value pairs up to 25 KB — connection strings, API keys, passwords. Key Vault stores the value but has no opinion about its format; encryption and decryption of the secret bytes at rest is the only cryptographic operation Key Vault performs on a secret.
- Keys
-
Cryptographic key material (RSA, EC, and, in preview, symmetric/OCT) that never leaves the vault in plaintext. Callers ask the vault to use the key —
encrypt/decrypt,wrapKey/unwrapKey,sign/verify— rather than retrieving key bytes, which is what lets services such as Azure Storage’s customer-managed keys or SQL Transparent Data Encryption use a Key Vault key without ever holding it. - Certificates
-
A managed convenience layer over keys and secrets: creating a certificate creates an addressable key (for the private key operations) and secret (for the full certificate plus private key, retrievable as a PFX/PEM blob) under the same name, alongside the public x509 metadata. Key Vault can generate the key pair, create and submit a signing request to an integrated CA (DigiCert or GlobalSign) or a non-integrated one, or import an existing certificate, and can auto-renew on a schedule (Certificates and rotation).
Standard vs. Premium vs. Managed HSM
| Tier | What it changes |
|---|---|
Standard |
Software-protected keys, encrypted with FIPS 140 Level 1-validated software cryptographic modules. Secrets and certificates behave identically on both tiers; only key protection differs. |
Premium |
The same vault and API, but keys can additionally be created as HSM-protected ( |
Managed HSM |
A different resource type ( |
Azure RBAC vs. access policies
Every vault is authorized one of two ways, and this is the one place on this site where the underlying API version genuinely changes default behavior rather than just adding flags:
-
Azure RBAC (
enableRbacAuthorization: true) — the same role-assignment model covered on Identity and Access, with Key-Vault-specific data-plane roles (below). One place to manage both control-plane and data-plane access, scoped down to an individual secret/key/certificate if needed, and the model Microsoft recommends for new vaults. -
Vault access policies (legacy) (
enableRbacAuthorization: false) — a list of principals and theget/list/set/… permissions each has, stored on the vault itself rather than as Azure role assignments. Still fully supported, but aContributoron the vault’s control plane can grant themselves a data-plane access policy, which is the main reason Azure RBAC is now recommended over it.
As of Key Vault control-plane API version 2026-02-01, creating a vault with that API version or later defaults
enableRbacAuthorization to true — Azure RBAC — unless the create call explicitly sets it to false. This
default applies only at create time: updating an existing vault with API 2026-02-01\+ does not change its
current access-control model, and a vault whose enableRbacAuthorization is null (created with an older API)
keeps using access policies until someone changes it. Separately — and this is the deadline to actually plan
around — every Key Vault control-plane API version before 2026-02-01 is retired on 2027-02-27; after that
date, calls made with an older API version are suspended, independent of which access-control model a vault
uses. Azure CLI 2.90.0\+ and Azure PowerShell 16.3.0\+ already call API 2026-02-01\+, so keeping the CLI
current is the simplest way to stay ahead of that retirement. kv-bookshelf is created below with Azure RBAC,
matching the current default.
Data-plane roles
| Built-in role | Grants |
|---|---|
|
Every data-plane operation on every object type. No control-plane rights, no ability to manage role assignments. |
|
Read secret values (including a certificate’s private-key secret). |
|
Full secret lifecycle (create/update/delete/recover), no ability to read a certificate’s or key’s material outside secrets. |
|
Every certificate operation except managing permissions — create, import, set rotation policy, delete. |
|
Read a certificate’s full content, including its private-key secret portion. |
|
Use keys for cryptographic operations (encrypt/decrypt/sign/verify) vs. full key lifecycle management, respectively. |
|
Read key metadata and perform wrap/unwrap only — the role Azure services such as Storage or SQL use for customer-managed-key encryption. |
|
Read metadata (names, tags, versions) of every object type, never a secret value or key material. |
|
Permanently purge a soft-deleted vault or object — see Soft delete and purge protection. |
|
Manage role assignments for the roles above, without itself getting any data-plane access. |
Key Vault Contributor is a control-plane role (manage the vault resource, its network rules, its tags) and
grants no access to secret, key, or certificate values on a vault that uses Azure RBAC.
In the Azure portal
-
Search for Key vaults and select Create.
-
Basics:
$RG, vault namekv-bookshelf, region, pricing tier (Standard), and leave Permission model at Azure role-based access control (the portal default matches the API default described above). -
Access configuration: confirm Azure role-based access control; adjust Days to retain deleted vaults (7—90, default 90) and toggle Enable purge protection here if wanted at creation time (Soft delete and purge protection).
-
Networking: leave Public access enabled for now (Networking below revisits this).
-
Review + create, then Create.
-
To assign a data-plane role: open the vault’s Access control (IAM) blade — the same flow as Identity and Access, searching for
Key Vault Secrets Useror the role needed.
With the Azure CLI
az keyvault create \
--name kv-bookshelf \
--resource-group "$RG" \
--location "$LOCATION" \
--sku standard \
--enable-rbac-authorization true \
--retention-days 90
Derived from Azure CLI reference — az keyvault create.
# catalog-api's managed identity: read-only access to secrets
az role assignment create \
--assignee-object-id "$(az identity show --name id-catalog-api --resource-group "$RG" --query principalId -o tsv)" \
--assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope "$(az keyvault show --name kv-bookshelf --query id -o tsv)"
Soft delete and purge protection
Soft delete is on by default for every vault and, once enabled, can never be turned off. Deleting a vault, or an
individual secret/key/certificate, does not remove it immediately: it moves to a soft-deleted state, listable
and recoverable for a retention period configurable only at creation time, from 7 to 90 days (default 90) — the --retention-days flag above. A second, explicit purge operation is required to permanently remove a
soft-deleted vault or object, and only a principal holding Key Vault Purge Operator (or, for a vault itself, a
subscription Owner) can issue it. Two consequences worth planning around: a vault name (and, within a vault, an
object name) cannot be reused until the retention period expires or the soft-deleted item is purged, and
recovering a soft-deleted vault does not restore services that were integrated with it, such as Azure RBAC
role assignments scoped to the vault or Event Grid subscriptions on it — those must be recreated.
Purge protection is an optional, one-way addition on top of soft delete: once enabled, nobody — not even a
subscription Owner — can purge a soft-deleted vault or object before its retention period elapses; it can only
expire naturally or be recovered. Most Azure services that use customer-managed keys (Storage, SQL) require
purge protection on the vault they point at, to prevent a key’s premature purge from causing permanent data
loss. kv-bookshelf enables it below; production vaults holding encryption keys should always enable it. The
flip side, for a walkthrough like this one: once purge protection is on, kv-bookshelf cannot be purged after it
is deleted, so its name stays reserved for the full 90-day retention period (see Clean up). Skip the
purge-protection step on a throwaway learning vault whose name you want to reuse immediately.
In the Azure portal
-
Enable purge protection: open
kv-bookshelf→ Settings → Properties, select Enable purge protection (enforce a mandatory retention period for deleted vaults and vault objects), then Save. The retention period shown there was fixed at creation and can’t be changed. -
Deleted secrets, keys, or certificates: open
kv-bookshelf→ Objects → Secrets (or Keys / Certificates) → Manage deleted secrets, select the item, then Recover (or Purge, which is refused while purge protection is on). -
Deleted vaults: search for Key vaults (the service, not an individual vault) → Manage deleted vaults, pick the subscription, tick the vault, then Recover (or Purge, again refused under purge protection).
With the Azure CLI
az keyvault update \
--name kv-bookshelf \
--resource-group "$RG" \
--enable-purge-protection true
# List soft-deleted vaults/objects and their recovery windows
az keyvault list-deleted --resource-type vault --output table
az keyvault secret list-deleted --vault-name kv-bookshelf --output table
# Recover a soft-deleted secret, or a whole soft-deleted vault
az keyvault secret recover --vault-name kv-bookshelf --name orders-db-connection-string
az keyvault recover --name kv-bookshelf
Derived from Azure Key Vault soft-delete overview and Azure Key Vault recovery overview.
Secrets: create, read, list, versions, and lifetime
Every write to a secret creates a new, immutable version; reading a secret by name without a version returns
the latest one. Both secrets and keys accept optional not-before and expires timestamps, enforced by the
data plane itself (an expired secret’s value cannot be retrieved even by a principal with full permissions) — Bookshelf sets these on anything with a known rotation cadence, such as a partner API key.
In the Azure portal
-
Open
kv-bookshelf→ Objects → Secrets → Generate/Import. -
Upload options: Manual; enter a Name and Value; optionally set Activation date and Expiration date.
-
Create. Selecting an existing secret shows every version and lets a new one be added the same way.
With the Azure CLI
az keyvault secret set \
--vault-name kv-bookshelf \
--name orders-db-connection-string \
--value "<secret-value>" \
--expires "2027-01-01T00:00:00Z"
az keyvault secret show --vault-name kv-bookshelf --name orders-db-connection-string
az keyvault secret list --vault-name kv-bookshelf --output table
az keyvault secret list-versions --vault-name kv-bookshelf --name orders-db-connection-string --output table
Derived from Azure CLI reference — az keyvault secret.
Certificates and rotation
Creating a certificate with az keyvault certificate create and a policy (subject name, key type, validity
period, issuer, and lifetime actions) drives the whole lifecycle: Key Vault generates the key pair, requests
or self-issues the certificate per the policy, and stores the result as an addressable key + secret
certificate. The default policy (az keyvault certificate get-default-policy) is a self-signed certificate with
an AutoRenew lifetime action triggered at 80% of its validity period elapsed; a custom policy can instead
trigger on EmailContacts only, or at a specific day count before expiry. Renewing an integrated-CA or
self-signed certificate this way creates a new secret version automatically; a non-integrated-CA certificate
instead produces a certificate signing request (CSR) to download, sign externally, and merge back in.
In the Azure portal
-
Open
kv-bookshelf→ Objects → Certificates → Generate/Import. -
Method of Certificate Creation: Generate; set Certificate Name, Subject (
CN=orders-api.bookshelf.example), Type of Certificate Authority (Self-signed or an integrated CA), and Content Type. -
Under Advanced Policy Configuration, set Validity Period and the lifetime action (percentage- or days-before-expiry-triggered,
Email ContactsorAuto Renew). -
Create. To renew manually ahead of the policy trigger, open the certificate and select New Version.
-
Add certificate contacts (Certificates → Certificate Contacts) so lifecycle notifications have somewhere to go.
With the Azure CLI
az keyvault certificate create \
--vault-name kv-bookshelf \
--name orders-api-tls \
--policy "$(az keyvault certificate get-default-policy)"
# Force a renewal ahead of the policy's own trigger
az keyvault certificate create \
--vault-name kv-bookshelf \
--name orders-api-tls \
--policy "$(az keyvault certificate policy show --vault-name kv-bookshelf --certificate-name orders-api-tls)"
az keyvault certificate list-versions --vault-name kv-bookshelf --name orders-api-tls --output table
Near-expiry events via Event Grid
Key Vault publishes object lifecycle events directly to Event Grid — no polling required. The events relevant
to expiry are Microsoft.KeyVault.CertificateNearExpiry and Microsoft.KeyVault.SecretNearExpiry, both fired a
fixed 30 days before the object’s current version expires, plus Microsoft.KeyVault.CertificateExpired /
SecretExpired once it has. A key’s near-expiry event, Microsoft.KeyVault.KeyNearExpiry, instead fires
whenever the key’s own rotation policy schedules it. Subscribing an Azure Function or Logic App to these lets
Bookshelf alert on a certificate that a CA-side renewal failed to pick up, independent of the vault’s own
AutoRenew action.
In the Azure portal
-
Open
kv-bookshelf→ Events → + Event Subscription. -
Name it
orders-api-cert-expiry, keep Event Grid Schema, and under Filter to Event Types keep only Certificate Near Expiry and Secret Near Expiry. -
Set Endpoint Type to Azure Function, choose Configure an endpoint, select the
notifierfunction app and itsCertExpiryHandlerfunction (an Event Grid-triggered function), then Confirm Selection → Create.
With the Azure CLI
az eventgrid event-subscription create \
--name orders-api-cert-expiry \
--source-resource-id "$(az keyvault show --name kv-bookshelf --query id -o tsv)" \
--endpoint-type azurefunction \
--endpoint "$(az functionapp function show --name notifier --resource-group "$RG" --function-name CertExpiryHandler --query id -o tsv)" \
--included-event-types Microsoft.KeyVault.CertificateNearExpiry Microsoft.KeyVault.SecretNearExpiry
Networking
A newly created vault’s firewall is disabled by default: every Azure service and public caller can reach the data-plane endpoint, though Microsoft Entra authentication and role/policy checks still gate every operation — disabling the firewall does not disable authorization. Enabling the firewall moves to a default-deny model with explicit allow rules:
-
Trusted Microsoft services bypass — lets services Microsoft fully controls the code for (a defined, documented list) reach the vault without a separate rule, even when public network access is fully disabled; services outside that list (Azure DevOps, for instance) always need an explicit rule or a private endpoint.
-
IP rules — public IPv4 addresses or CIDR ranges, up to 1000, for callers with static egress IPs.
-
Virtual network rules — a specific subnet, via a
Microsoft.KeyVaultservice endpoint, for callers with dynamic IPs inside a VNet (e.g. VM Scale Sets). -
Private endpoint — a private IP for the vault inside a VNet, via Azure Private Link; combined with disabling public network access entirely, this is the only configuration under which the data plane is reachable exclusively from inside chosen VNets. The vault’s public DNS name still resolves (by design, part of the Private Link DNS overlay every Azure PaaS service uses) but every data-plane request to the public endpoint is refused once public access is disabled.
In the Azure portal
-
Open
kv-bookshelf→ Networking. -
Firewalls and virtual networks tab: choose Allow public access from specific virtual networks and IP addresses or Disable public access; add virtual network/subnet or IP rules as needed; toggle Allow trusted Microsoft services to bypass this firewall.
-
Private endpoint connections tab: + Create a private endpoint into
vnet-bookshelf, approving the DNS zone group sokv-bookshelf.vault.azure.netresolves to the private IP from inside the VNet.
With the Azure CLI
subnetid=$(az network vnet subnet show --resource-group "$RG" --vnet-name vnet-bookshelf --name snet-apps --query id -o tsv)
az keyvault network-rule add --resource-group "$RG" --name kv-bookshelf --subnet "$subnetid"
az keyvault update --resource-group "$RG" --name kv-bookshelf --default-action Deny --bypass AzureServices
Derived from Configure network security for Azure Key Vault.
Consumption patterns
Bookshelf reads secrets from kv-bookshelf four different ways, chosen per compute host rather than per secret.
Path 1: the SDK with DefaultAzureCredential
catalog-api and orders-api call kv-bookshelf directly, exactly as shown on
Identity and Access: SecretClient (Java) or the Spring Cloud Azure Key Vault starter
authenticate with DefaultAzureCredential, which resolves to the app’s managed identity in every deployed
environment and to the developer’s own az login session locally, with no code branch between the two. This is
the right default whenever the application needs to read a secret at an arbitrary point in its own logic (not
just at startup), or needs more than one version of a secret at once.
Path 2: Key Vault references (App Service, Functions, Container Apps)
A Key Vault reference lets a platform resolve a secret into a configuration value without any application code touching the Key Vault SDK at all — the app reads an ordinary environment variable or app setting, and the platform substitutes the real value at runtime using its own managed identity.
- App Service and Azure Functions
-
An app setting or connection string whose value is
@Microsoft.KeyVault(SecretUri=https://kv-bookshelf.vault.azure.net/secrets/orders-db-connection-string)(or the equivalentVaultName=…;SecretName=…form). The referenced managed identity — system-assigned by default, or a chosen user-assigned identity viakeyVaultReferenceIdentity— needsKey Vault Secrets User(Azure RBAC) or agetaccess policy. If no version is pinned in the URI, the platform resolves the latest version and caches it for 24 hours, re-fetching automatically on that schedule or immediately on any setting change (which restarts the app); a management-plane POST to the app’sconfig/configreferences/appsettings/refreshendpoint forces an out-of-band refresh. See App Service and Azure Functions for where these settings live in the app model. - Container Apps
-
A secret defined with
--secrets "name=keyvaultref:<secret-uri>,identityref:<managed-identity-id>", referenced from a container’s environment variables withsecretref:name, exactly as introduced on Container Apps. Only a user-assigned identity can be used atcontainerapp createtime (a system-assigned identity does not exist yet); it must holdKey Vault Secrets Useronkv-bookshelf. If the secret URI omits a version, Container Apps polls Key Vault roughly every 30 minutes and, on finding a newer version, automatically restarts every active revision that references it in an environment variable to pick up the change.
az containerapp create \
--resource-group "$RG" \
--name orders-api \
--environment cae-bookshelf \
--image "$ACR.azurecr.io/orders-api:latest" \
--user-assigned "$(az identity show --name id-orders-api --resource-group "$RG" --query id -o tsv)" \
--secrets "orders-db-connection-string=keyvaultref:https://kv-bookshelf.vault.azure.net/secrets/orders-db-connection-string,identityref:$(az identity show --name id-orders-api --resource-group "$RG" --query id -o tsv)" \
--env-vars "SPRING_DATASOURCE_URL=secretref:orders-db-connection-string"
Path 3: the AKS Secrets Store CSI driver with workload identity
On aks-bookshelf, a workload requests secrets through the Azure Key Vault provider for Secrets Store CSI
Driver rather than either of the paths above. The driver is enabled per cluster
(--enable-addons azure-keyvault-secrets-provider), authenticates using Microsoft Entra Workload ID — the same
federated-credential mechanism described on Identity and Access and used by
Deploying Microservices on AKS's workload identity setup — and exposes secrets as files in a CSI
volume, backed by a SecretProviderClass custom resource:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: kv-bookshelf-secrets
namespace: bookshelf
spec:
provider: azure
parameters:
usePodIdentity: "false"
clientID: "<workload-identity-client-id>"
keyvaultName: kv-bookshelf
tenantId: "<tenant-id>"
objects: |
array:
- |
objectName: orders-db-connection-string
objectType: secret
- |
objectName: orders-api-tls
objectType: cert
secretObjects:
- secretName: orders-db-secret
type: Opaque
data:
- objectName: orders-db-connection-string
key: connection-string
The objects array is what the driver mounts as files under /mnt/secrets-store; the optional secretObjects
block additionally syncs those same values into a native Kubernetes Secret (orders-db-secret above), so
workloads that expect a regular Secret volume or envFrom reference can consume it without knowing Key Vault
is involved — Deploying Microservices on AKS and
Configuration and Profiles's Kubernetes ConfigMaps and Secrets section cover
consuming that synced Secret from the pod side. The service account referenced by the pod carries an
azure.workload.identity/client-id annotation matching the same identity, and that identity needs Key Vault
Secrets User (for secret objects) and/or Key Vault Certificate User (for key/cert objects) on
kv-bookshelf.
Rotation is opt-in and separate from the platform paths above: enabling it (--enable-secret-rotation on
az aks addon update) makes the driver re-poll Key Vault on an interval — rotationPollInterval, 2 minutes
by default — updating both the mounted files and any synced Secret when a newer version appears. A pod using
a Secret as a subPath volume mount is a documented exception: Kubernetes itself does not propagate updates to
a subPath mount, so that pattern needs an application-side reload or restart regardless of how fast the driver
rotates.
az aks create \
--name aks-bookshelf \
--resource-group "$RG" \
--enable-addons azure-keyvault-secrets-provider \
--enable-oidc-issuer \
--enable-workload-identity \
--generate-ssh-keys
az role assignment create \
--role "Key Vault Secrets User" \
--assignee-object-id "$(az identity show --name id-orders-api-aks --resource-group "$RG" --query principalId -o tsv)" \
--assignee-principal-type ServicePrincipal \
--scope "$(az keyvault show --name kv-bookshelf --query id -o tsv)"
GitHub Actions secrets vs. Key Vault
A GitHub Actions repository/environment secret and a Key Vault secret solve different problems and Bookshelf uses both. A GitHub secret is scoped to the workflow that consumes it, has no versioning, no expiry, and no audit trail beyond the workflow run log — it is the right place for values a workflow itself needs (a short-lived deployment parameter, a third-party API token used only in CI). A Key Vault secret is the right place for anything a running application needs, since it is versioned, can carry an expiry, is covered by soft delete, and is readable by a managed identity with no credential ever stored in the repository at all. The workflow that deploys Bookshelf typically needs neither a stored Key Vault secret nor a stored client secret to authenticate to Azure in the first place — it authenticates via workload identity federation (Identity and Access, and the mechanics on Docker CI/CD with GitHub Actions) — and then either deploys a Container App whose own Key Vault reference resolves secrets at runtime, or writes a small number of CI-only values as GitHub secrets.
Logging and auditing
Key Vault does not log data-plane access by default; enabling it is a per-vault diagnostic setting, same as any
other Azure resource, sending the AuditEvent (every data-plane call, its caller, and its result) and
AzurePolicyEvaluationDetails categories to a Log Analytics workspace, a storage account, or an event hub. This
is the audit trail that shows who read orders-db-connection-string and when, independent of Azure RBAC’s
own activity log (which covers control-plane changes to the vault, not data-plane reads).
az monitor diagnostic-settings create \
--name kv-bookshelf-diagnostics \
--resource "$(az keyvault show --name kv-bookshelf --query id -o tsv)" \
--workspace "$(az monitor log-analytics workspace show --resource-group "$RG" --workspace-name law-bookshelf --query id -o tsv)" \
--logs '[{"category":"AuditEvent","enabled":true}]'
Derived from Azure Key Vault logging.
Cost
Standard and Premium vaults bill per operation (secret/key/certificate get, set, list, …) plus a small
per-managed-key monthly charge for HSM-protected (Premium) keys and per-renewal charge for managed certificates — the dominant driver in practice is operation volume, which is why Path 2’s 24-hour/30-minute caching and
Path 3’s CSI volume mount (read from the mounted file, not a fresh Key Vault call per request) matter as much
for cost as for latency: an application that called SecretClient.getSecret on every request instead of caching
it in memory would multiply its Key Vault bill by its request volume for no benefit, since the underlying
secret rarely changes between requests. A soft-deleted object in the retention window bills nothing except its
own purge/recover calls (and, for an HSM key, its per-version monthly charge if used within the last 30
days). Managed HSM bills per HSM pool per hour instead of per operation, which is the other reason it is
reserved for workloads that actually need a dedicated hardware boundary. Current rates are on the
Key Vault pricing page, which should be checked before
sizing any of the above for a real workload.
Troubleshooting
-
A Key Vault reference shows as unresolved text (
@Microsoft.KeyVault(…)) instead of its value in App Service/Functions — almost always a missing role assignment/access policy on the referenced identity, or a syntax error in the reference string; the Key Vault Application Settings Diagnostics detector under Diagnose and solve problems narrows it down further than the app setting’s own edit-dialog status. -
A Container Apps secret update never reaches a running revision — expected: secrets are application-scoped and updating one does not create a new revision by itself; deploy a new revision or restart the existing one, and remember the ~30-minute Key Vault poll interval if the vault-side value changed rather than the reference itself.
-
A pod using the Secrets Store CSI driver fails to start with an identity or permission error — check the
SecretProviderClass’s `clientID/tenantIdmatch the workload identity actually federated for that service account, and that the identity holdsKey Vault Secrets User(orKey Vault Certificate Userforkey/certobjects) on the vault;kubectl describe podsurfaces the driver’s own mount error in the pod’s events. -
A vault or secret name cannot be reused — it is still inside another object’s soft-delete retention window; either wait it out, recover it, or purge it (with
Key Vault Purge Operator) if it is genuinely unwanted. -
A firewall-enabled vault returns 403 from the Azure portal itself — the portal’s own network origin isn’t on the allow list; add the client machine’s egress IP or a private endpoint reachable from wherever the portal is being used, per Networking.
Clean up
az group delete --name "$RG" --yes
# kv-bookshelf is now soft-deleted, not gone -- confirm it and note its scheduled purge date
az keyvault list-deleted --resource-type vault \
--query "[?name=='kv-bookshelf'].{name:name, purgeDate:properties.scheduledPurgeDate}" --output table
Because purge protection is enabled on kv-bookshelf, az keyvault purge is refused: the vault
stays soft-deleted, and its name reserved, until the 90-day retention period set at creation elapses, after which
Azure purges it automatically. Within that window it can still be brought back with az keyvault recover --name
kv-bookshelf. For a disposable vault created without purge protection, az keyvault purge --name <vault>
--location "$LOCATION" frees the name immediately — but only after the resource-group deletion has finished
(hence no --no-wait above), since a vault can’t be purged before it has been soft-deleted.
Derived from Azure Key Vault recovery overview.
Related pages
-
Identity and Access covers Azure RBAC, managed identities, and
DefaultAzureCredentialin depth; this page only covers what is specific to Key Vault’s own data-plane roles. -
Container Apps and App Service and Azure Functions cover the Secrets blade and app settings that Key Vault references plug into.
-
Deploying Microservices on AKS and AKS Clusters cover workload identity setup and cluster-level add-ons in more depth than the CSI-driver-focused summary above.
-
Runtime Configuration covers configuration and feature flags — the values that live alongside, but are not, secrets — including App Configuration’s own Key Vault references.
-
Configuration and Profiles covers Kubernetes ConfigMaps and Secrets from the Spring Boot application side.
-
Docker CI/CD with GitHub Actions covers the GitHub Actions workflow mechanics behind the workload identity federation used to deploy Bookshelf without a stored credential.
References
-
Microsoft Learn — Plan for Azure RBAC as the default access control model in Key Vault
-
Microsoft Learn — Provide access to Key Vault keys, certificates, and secrets with Azure RBAC
-
Microsoft Learn — Azure CLI reference: az keyvault certificate
-
Microsoft Learn — Configure network security for Azure Key Vault
-
Microsoft Learn — Use the Azure Key Vault provider for Secrets Store CSI Driver for AKS
-
Microsoft Learn — Access Azure Key Vault with the CSI Driver identity provider