Runbooks / Secrets Keyvault

Secrets in Azure Key Vault

IdentityMesh ships with two secret-store backends:

ProviderWhen to use
DPAPI (default)On-prem deployments, single host, no cloud dependency. See secrets-and-dpapi.md.
Azure Key VaultCloud or hybrid deployments where secrets must travel across hosts (HA failover, DR rebuild) or are governed by a central vault policy.

This document covers the Key Vault provider.

Why Key Vault

The DPAPI provider encrypts each secret blob with the host’s LocalMachine key. That key never leaves the host, so the blobs are not portable: a re-image, a DR rebuild, or a cluster failover to a second host all require re-provisioning every connector secret by hand.

Key Vault keeps the ciphertext in the vault, not on the host. Any authorised IdentityMesh process — original host, replacement host, DR-region host — can read the same secret using the same vault URI and an authenticated managed identity.

Enabling Key Vault

In the sync engine’s appsettings.json:

{
  "Secrets": {
    "Provider": "AzureKeyVault",
    "KeyVault": {
      "VaultUri": "https://contoso-im.vault.azure.net/"
    }
  }
}

When Secrets:Provider is unset or any value other than AzureKeyVault, IdentityMesh uses the DPAPI store and Key Vault configuration is ignored. So flipping the switch is the only deployment change required.

Authentication

The engine uses DefaultAzureCredential from the Azure SDK to acquire a token for the vault. That credential walks a chain of sources in this order:

  1. Environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET for service principal; or AZURE_FEDERATED_TOKEN_FILE for workload identity).
  2. Managed identity assigned to the host (system-assigned VM identity, or a user-assigned identity referenced by AZURE_CLIENT_ID). This is the recommended setup in production.
  3. Azure CLI session (az login) — useful for development and first-touch provisioning, not for production.

Whichever identity the host ends up using needs the Key Vault Secrets User role on the vault (and Key Vault Secrets Officer if it will write secrets, e.g. via the Admin UI).

Secret naming

Callers pass arbitrary refs (e.g. secret://ad/svc/password) but Key Vault names allow only [A-Za-z0-9-] and must start with a letter. IdentityMesh maps each ref to a stable Key Vault name:

secretRef  →  "im-" + lowercase-hex(SHA-256(secretRef))[:32]

For example, secret://ad/svc/password becomes im-3f2a1b... — predictable, collision-resistant, and never truncates a long ref. The engine logs the mapping at INFO when it writes a secret, so you can correlate refs to vault entries when needed.

The mapping is one-way (you can’t recover the original ref from the vault name). Keep the ref strings in your connector configs as the canonical identifier; the vault name is an implementation detail.

Provisioning a secret

Secrets are still provisioned via the Admin UI / Admin API exactly as they are with the DPAPI store. The engine handles the encoding-and-storage step transparently:

  1. Operator enters the cleartext in the Admin UI.
  2. The Admin API calls ISecretStore.SetAsync(ref, bytes).
  3. With Secrets:Provider = AzureKeyVault, that resolves to the Key Vault store, which Base64-encodes the bytes and calls SetSecret on the configured vault.
  4. The connector config keeps only the ref. Rotation is ref-stable: re-setting the same ref creates a new vault version, the engine always reads the current version.

What if the vault is unreachable

The engine attempts to read the secret on each connector run. If Key Vault is unreachable (network outage, identity revoked, vault deleted) the connector run fails with the underlying SDK error surfaced. The watermark is not advanced, so the next run re-tries from the last good checkpoint.

For longer outages, vault availability — not IdentityMesh — is the SLA you should monitor. Use the Azure status page and per-vault metrics to decide whether the engine is the right place to alert.

Migration from DPAPI to Key Vault

There is no automated migration today. The procedure is:

  1. Provision the vault and grant the engine’s identity Key Vault Secrets Officer.
  2. Take the engine offline.
  3. For each secret in the existing DPAPI store, re-enter the cleartext via the Admin UI. With Secrets:Provider already flipped to AzureKeyVault in the engine’s config, the new value lands in the vault under its mapped name.
  4. Restart the engine.

The DPAPI rows in IM_Secrets remain in the database after migration. They are unused but harmless; an explicit cleanup pass can purge them once you’re confident the vault store is the source of truth.