Why is searching Azure Key Vault secrets difficult?
Key Vault exists to store secrets and hand them to applications securely. Its API is built around get, list, set, and delete, and it was never meant to be something people browse. When customers have asked for a search box in the portal, the response on Microsoft Q&A has been that it shouldn't be needed, because Microsoft's guidance is to keep one vault per application, per region, and per environment. Each vault stays small enough to read through by eye.
That holds up for a single application. It falls apart once you add the vaults up. One app following the guidance already has:
myapp-dev
myapp-staging
myapp-production
Now repeat that for every application, and again for every other reason an organization splits vaults:
- QA and preproduction environments
- Regions
- Customers and tenants
- Franchise locations
- Separate Azure subscriptions
Once the count reaches the dozens, "Where is the Stripe API secret?" stops being a quick check. You're opening vaults one at a time and hoping you picked the right one first.
Can Azure Key Vault search for a secret by name?
Not from the portal, and not on the server side either. The Key Vault API can list the secrets in a vault, which returns names and metadata but never values, and any filtering happens after the list comes back. There's no name-contains query and no tag filter.
Inside a single vault, the CLI or PowerShell will get you there:
# Secret names in one vault that contain "stripe" (case-insensitive)
az keyvault secret list --vault-name myapp-production --query "[].name" -o tsv | grep -i stripe
# Same idea, keeping the enabled flag (JMESPath contains() is case-sensitive)
az keyvault secret list --vault-name myapp-production \
--query "[?contains(name, 'Stripe')].{name:name, enabled:attributes.enabled}" -o table
Get-AzKeyVaultSecret -VaultName myapp-production |
Where-Object Name -like '*stripe*' |
Select-Object Name, Enabled, Expires, Tags
Two things trip people up. JMESPath's contains() is
case-sensitive, so stripe won't match
Stripe--SecretKey. And the list call returns disabled secrets
alongside enabled ones, so check the enabled flag before you trust a hit.
What happens when you have dozens or hundreds of Key Vaults?
The question stops being "Where is my secret?" and becomes "Which vault has my secret?"
A SaaS product that deploys a dedicated environment per customer is a good example, and it's a pattern Microsoft's multitenant guidance covers:
Customer A
├── Development Key Vault
├── Staging Key Vault
└── Production Key Vault
Customer B
├── Development Key Vault
├── Staging Key Vault
└── Production Key Vault
Customer C
├── Development Key Vault
├── Staging Key Vault
└── Production Key Vault
Three customers is nine vaults. Forty customers is 120, each holding dozens of secrets, and nobody carries that map around in their head. Standing each of those vaults up in the first place is a related problem, covered in copying secrets to another Key Vault.
Two situations make it hurt. The first is rotation. When a Stripe key gets rolled or a credential leaks, you need every place a copy lives, and the vault you miss is the one that breaks later or stays exposed. The second is drift. Staging works and production doesn't because a secret was added to one vault and never made it to the other. Finding which vaults are missing a secret is a search problem too, and it will happen more often than a leak.
What is the best way to search across Azure Key Vaults?
It depends on how many vaults you have and how often anyone needs to search. There are three approaches, and they build on each other more than they compete.
1. Write a script or build your own internal tool
Start with an inventory of vaults. Azure Resource Graph is the quickest way, since it can query across subscriptions in a single call:
az extension add --name resource-graph
az graph query --first 1000 -q "
resources
| where type =~ 'microsoft.keyvault/vaults'
| project name, subscriptionId, resourceGroup, location, tags"
Pass --first 1000 because the default page is small, and check the
subscription and management group scope options if the list looks short.
From there, a loop over the vaults is enough for a small estate:
#!/usr/bin/env bash
# Usage: ./kv-find.sh stripe
term="$1"
for vault in $(az graph query --first 1000 \
-q "resources | where type =~ 'microsoft.keyvault/vaults' | project name" \
--query "data[].name" -o tsv); do
if ! names=$(az keyvault secret list --vault-name "$vault" --query "[].name" -o tsv 2>/dev/null); then
echo "SKIPPED (no access or blocked): $vault" >&2
continue
fi
echo "$names" | grep -i -- "$term" | sed "s/^/$vault: /"
done
If you're building something more permanent in .NET, the same idea with the SDK
looks like this. It needs the Azure.Identity,
Azure.ResourceManager, Azure.ResourceManager.KeyVault,
and Azure.Security.KeyVault.Secrets packages:
using Azure;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.KeyVault;
using Azure.Security.KeyVault.Secrets;
var term = args.Length > 0 ? args[0] : throw new ArgumentException("Usage: kvfind <term>");
var credential = new DefaultAzureCredential();
var arm = new ArmClient(credential);
await foreach (var subscription in arm.GetSubscriptions().GetAllAsync())
{
await foreach (var vault in subscription.GetKeyVaultsAsync())
{
var client = new SecretClient(vault.Data.Properties.VaultUri, credential);
try
{
await foreach (var secret in client.GetPropertiesOfSecretsAsync())
{
if (secret.Name.Contains(term, StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine($"{subscription.Data.DisplayName} / {vault.Data.Name} / {secret.Name}");
}
}
}
catch (RequestFailedException ex)
{
// A vault you couldn't read is not the same as a vault with no match.
Console.Error.WriteLine($"SKIPPED {vault.Data.Name}: HTTP {ex.Status}");
}
}
}
A few things matter more than the search loop itself:
- Report the vaults you couldn't read. A vault behind a firewall, a private endpoint, or a missing role assignment looks exactly like a vault with no match unless the tool says otherwise. Both examples above print the ones they skip.
- Grant the minimum. Listing names and metadata needs a metadata role such as Key Vault Reader on vaults that use the RBAC permission model. Handing out Key Vault Secrets User so people can search gives them the values too.
- Index names, not values. If you cache results, store the subscription, vault, secret name, tags, and expiry. Never copy secret values into an index.
- Mind the throttle. Key Vault throttles per vault, and the service limits allow 4,000 non-create operations per 10 seconds per vault. Listing rarely gets close, but fanning out across vaults with a bounded degree of parallelism beats hammering one. The SDK retries 429 responses with backoff by default.
- Decide how the index refreshes. A stale index that points to a secret that no longer exists is worse than a slow live search.
For a handful of vaults, that's a perfectly good answer. Past that, you're maintaining authentication, subscription and vault discovery, permissions, caching, and a UI, and none of it is the product you're actually shipping.
2. Use a centralized Key Vault management tool
A management layer takes over the enumeration, the permission handling, and the search. Instead of navigating
Azure Portal → Subscription → Resource Group → Key Vault → Secrets
for every vault, you search for a name and see each vault that has a match. That pays off most when your vaults are spread across environments, subscriptions, regions, or customers.
KickCatch Secrets Manager is one option. It sits on top of the vaults you already have, searches secret names across vaults and subscriptions, and works through your existing Azure account instead of asking you to move secrets into a separate store.
Whichever tool you evaluate, this one or another, ask a few questions first:
- Does it copy secret values into its own storage, or read them from Key Vault when needed?
- Does it act as the signed-in user, so your RBAC assignments still decide who sees what?
- Do its reads show up in the vault's own diagnostic logs?
- Can it reach the vaults behind the firewalls and private endpoints you use?
3. Adopt a naming convention and tag everything
This one isn't an alternative to the first two. It's what makes them work.
Secret names can only contain letters, digits, and dashes, up to 127
characters. In .NET the usual convention is a double dash as the separator,
because the Key Vault configuration provider turns -- into
:, so Stripe--SecretKey binds to
Stripe:SecretKey:
Database--ConnectionString
Stripe--SecretKey
SendGrid--ApiKey
ApplicationInsights--ConnectionString
Use the same secret names in every environment and change only the values.
Searching for Stripe--SecretKey then tells you exactly which
vaults have it and, by omission, which ones don't. That takes care of the drift
problem from earlier.
Vault names are tighter: 3 to 24 characters and globally unique. Something like
kv-billing-prod-eus (application, environment, region) works, but
24 characters can't carry everything, so put the rest in tags on the vault:
application, environment, customer, owner. Resource Graph can then answer "show
me every production vault for customer X" without touching a single secret. Tag
the secrets too, keeping in mind that you'll filter on those client-side after
listing.
A convention only holds if something enforces it. Azure Policy can require tags when a vault is created, and a naming check in your infrastructure-as-code pipeline catches most of the rest.
As a rough guide, a script and a convention are enough for around ten vaults or fewer. Somewhere in the tens, a shared tool starts to earn its keep, whether you build it or buy it. The bigger trigger is usually people: once someone other than the script's author needs to search, a script stops being enough.
Can I search Azure Key Vault by secret value?
Not directly. Key Vault has no API for it, so the only route is to read every secret and compare, which means a get call per secret and permission to read values in every vault you scan. It also makes noise. Every read lands in the audit logs, and a job that reads every secret in every vault looks a lot like an attacker taking inventory, which Defender for Key Vault or your own alerts may treat accordingly.
There's one case where it's worth doing: a credential has leaked and you need every vault that holds the same value. Run it once, under a time-limited elevated role such as one granted through Privileged Identity Management, compare against the known value in memory, and record only the vault and secret names. For everyday lookups, names and tags do the job.
Should you put all secrets in one Key Vault instead?
Usually not, and never only to make searching easier.
A vault is the security boundary. Role assignments that matter for managing secrets apply at the vault level (object-scope assignments only cover read operations), and firewall rules, private endpoints, and diagnostic settings are all per vault. Put every application's secrets in one vault and you either give each app access to secrets it has no business reading, or you try to scope access per secret and find that RBAC at that level only supports reads. That's why Microsoft's guidance calls for separate vaults by application, region, and environment, and one vault per tenant in multitenant SaaS.
There are exceptions. A small internal tool with a dozen secrets doesn't need three vaults. But if the vault count is what bothers you, that's a tooling problem, and it's cheaper to fix with tooling than by weakening isolation.
A better workflow for development teams
Instead of asking developers to remember which vault holds what, the search workflow should look like this:
- Search for a secret by name.
- See which vaults contain it.
- Identify the environment, customer, or region each vault belongs to.
- Open the secret using your existing Azure permissions.
- Where the same change applies to several vaults, update them together.
Step 5 needs a caution. A shared change is reasonable across the production vaults of every customer when a vendor changes an endpoint. It's a mistake across development and production, where the values are supposed to differ. KickCatch Secrets Manager is built around this flow, including updating a secret across multiple selected vaults, so the fan-out is a deliberate selection instead of a script loop with a typo in it.
Frequently asked questions
Can I search inside a single Key Vault from the Azure portal?
No. The secrets list is paged, with a "Load more" button, and has no search or
filter box. For a single vault, use az keyvault secret list with a
query, or Get-AzKeyVaultSecret piped into Where-Object.
Can I search all Azure Key Vaults from the Azure portal?
No. The search bar at the top of the portal finds resources, so it takes you to a vault by name, but it doesn't look inside the vault. Cross-vault search takes a script, your own tool, or a management layer.
Can Azure CLI search multiple Key Vaults?
Yes, but the CLI won't do it in one command. Use Resource Graph to list the vaults,
run az keyvault secret list against each one, and filter the names
yourself. Log the vaults you couldn't reach so a blocked vault isn't mistaken for a
miss.
Can I search Key Vault secrets by tag?
Yes, after the fact. The list API has no tag filter, so you list a vault's secrets
and filter on the tags client-side, for example with
--query "[?tags.owner=='payments']". Tags on the vaults themselves are
easier, since Resource Graph can filter on them directly.
What permissions do I need to list secrets?
On vaults that use RBAC, Key Vault Reader can list secret names and metadata without reading values, and Key Vault Secrets User can read the values. Vaults still on legacy access policies need the List secret permission in the policy. Microsoft recommends RBAC, and the RBAC guide covers the details.
Why can't I find a secret I know exists?
The usual causes are:
- It's in a different vault than the one you searched.
-
It was deleted. Soft-deleted secrets don't appear in the normal list; run
az keyvault secret list-deleted --vault-name <name>. - Your search skipped the vault because a firewall, private endpoint, or missing role blocked the list call.
-
A case-sensitive filter missed it.
contains(name, 'stripe')won't matchStripe--SecretKey.
Is Azure Key Vault a secret-management application?
Azure Key Vault is a secure service for storing and accessing secrets, keys, and certificates. It isn't an operations console for an organization with a large number of vaults, and that gap is what scripts and management tools fill.
Why would I have multiple Key Vaults?
Separate vaults give you security and operational boundaries between applications, environments, regions, and tenants. Microsoft's guidance recommends separate vaults for development, preproduction, and production, and, depending on the architecture, a vault per tenant in multitenant solutions.
How can I make managing multiple Key Vaults easier?
Use consistent secret and vault names, tag vaults with application, environment, and owner, and keep permissions narrow. Automate the repetitive operations, and add a management layer once enough people need to search and change secrets across vaults from one place.