Roadmap
Same discipline as fabric-emulator: each phase independently useful, real-SDK e2e-verified, ≥90% coverage floor in CI from the first commit.
P0 — secrets + the real auth handshake
Section titled “P0 — secrets + the real auth handshake”The core value: an Azure SDK acquires a token from entra-emulator via the challenge flow and round-trips secrets.
- Foundations: clock, config (
KV_*env + flags), store (vault, secret, secret_version, deleted_secret), self-signed TLS (*.vault.azure.net), Host-routed vault resolution + default seeded vault. - Auth: challenge
401advertising the entra authority; RS256 validation against entra JWKS (issuer, vault audience, clock-based expiry). Reuses the validator pattern from fabric-emulator’sinternal/auth. - Secrets: set/get/get-version/patch/list/list-versions (paged),
new-version-per-PUT,
enabledgating, informationalnbf/exp, backup/restore. - Soft delete: delete → deleted state with
scheduledPurgeDateon the clock; recover; purge; name-reuse conflict while deleted. -
/_emulatorclock + faults (incl. 429 throttling injection). - Docker (distroless) + docker-compose with entra-emulator (challenge authority pre-wired; vault resource app seeded via entra’s admin API).
- e2e (in-process entra, like fabric-emulator’s fixture): azsecrets +
azidentity.ClientSecretCredential complete the challenge flow
unmodified; managed-identity path via entra’s
/msi/token(IDENTITY_ENDPOINT/IDENTITY_HEADER); forged wrong-audience / expired tokens rejected; clock-advance expires a live token.
P1 — keys (real crypto) + hardening
Section titled “P1 — keys (real crypto) + hardening”- Keys CRUD/versions/soft-delete; RSA + EC generation (software-protected).
- sign/verify, encrypt/decrypt, wrap/unwrap with real Go crypto — output verifiable against the returned JWK.
- Optional per-principal permission map (
/_emulator/permissions) for authorization-denied paths. - e2e: azkeys SDK sign → local JWK verify; encrypt → decrypt round trip.
P2 — certificates
Section titled “P2 — certificates”- Certificates CRUD + policy; self-signed issuance; PFX/PEM import; linked key/secret materialization under the same name.
- e2e: azcertificates SDK create-self-signed → fetch → TLS-use the cert.
P3 — family integration
Section titled “P3 — family integration”- fabric-emulator AKV-reference connections resolve against this
emulator (its roadmap item, built on the fabric side):
workspace identity → entra token → vault secret → connection, fully offline. - e2e: the secret-as-SP-credential chain — the canonical “SP secret
lives in Key Vault” pattern across all three emulators
(
e2e/chain/run.py, in CI): a client-credentials call stores an SP secret in the vault, a managed-identity token (entra/msi/token, no credential in the workload) reads it back, that secret authenticates the SP to entra for a Fabric-audience token, and the token calls fabric-emulator. Three real processes; a wrong secret breaks the chain exactly where it would in Azure. - entra-emulator enhancement (shipped in entra v0.2.1): recognize
https://vault.azure.net(+ Storage, ARM) as well-known Azure resources, so client-credentials/MSI resolve the vault audience without seeding a resource app. - Compose file with all three emulators (
docker-compose.yml,fullprofile adds fabric).
P4 — SDK parity surface (shipped in v0.2.0)
Section titled “P4 — SDK parity surface (shipped in v0.2.0)”Round out the secondary operations the Azure SDKs expose beyond core CRUD, so a
test written against azkeys / azcertificates never hits an endpoint the
emulator lacks. Measured against the reference
james-gould emulator;
we keep our real-auth and real-crypto posture throughout. With these, the
emulator reaches full parity on the SDK-observable surface.
- Keys: import a caller-supplied JWK (
PUT /keys/{name}, real RSA/EC material — a subsequent sign/verify round-trips), update-latest (PATCH /keys/{name}), backup/restore, and rotation policy get/set. - GetRandomBytes (
POST /rng). - Certificates: backup/restore, update attributes/policy
(
PATCH /certificates/{name}), policy update (PATCH /certificates/{name}/policy), issuers (GET/PUT/PATCH/DELETE /certificates/issuers/{name}+ list) and contacts (GET/PUT/DELETE /certificates/contacts). - Secure Key Release (
POST /keys/{name}/{version}/release) — a genuine signed JWS carrying the released public JWK. No HSM attestation (there is no enclave to attest), so any enabled key is releasable; the call path and token shape are emulated. - Certificate CSR merge (
POST /certificates/{name}/pending/merge) — a named issuer creates a pending operation with a real PKCS#10 CSR; you sign it with your own CA and merge the chain back, completing the async-issuance path fully offline. A live third-party CA remains the only certificate non-goal (the emulator never phones out).
Cross-cutting (throughout)
Section titled “Cross-cutting (throughout)”- CI: vet/build/test + 90% coverage floor + the three-emulator chain e2e.
- Starlight docs site on GitHub Pages (
/docs= source of truth), live at https://calvinchengx.github.io/azure-keyvault-emulator/. - GoReleaser: binaries + distroless Docker (GHCR) + Homebrew + winget. v0.1.0 shipped P0–P3; v0.2.0 adds the full P4 parity surface (import, backup/restore, rng, rotation policy, key release, issuers, contacts, certificate CSR merge) and the operator portal.
- Svelte operator portal (v0.2.0) — dashboard,
secrets/keys/certificates/deleted views, clock + fault-injection
controls. Svelte 5, built to a committed
portal/dist, embedded viago:embed, served at/_emulator/portal/, with a CI drift guard + Playwright mount smoke. Mirrors the family pattern.
Sequencing note
Section titled “Sequencing note”Build the challenge handshake before any storage — it is this emulator’s reason to exist, every SDK call path runs through it, and it defines the integration contract with entra-emulator. Secrets storage is straightforward once auth is honest.