Keys
RSA and EC keys with the same versioning + soft-delete skeleton as secrets, plus cryptographic operations backed by real Go crypto — signatures verify against the JWK the API returns, not stubs. Software-protected only (no HSM).
Endpoints
Section titled “Endpoints”| Method + path | Purpose |
|---|---|
POST /keys/{name}/create | create — {kty, key_size?/crv?, key_ops?, attributes?, tags?} → key bundle |
PUT /keys/{name} | import a caller-supplied JWK ({key:{kty,…private members}, attributes?, tags?}) — or a BYOK transfer blob (key.key_hsm): the vault-held KEK named in the blob’s header genuinely undoes CKM_RSA_AES_KEY_WRAP (RSA-OAEP-SHA1 + AES-KWP) |
GET /keys/{name} | /keys/{name}/{version} | get the public JWK |
PATCH /keys/{name}/{version} | /keys/{name} | update key_ops/attributes/tags (versioned or latest) |
GET /keys | /keys/{name}/versions | list (paged) |
DELETE /keys/{name} | soft-delete |
POST /keys/{name}/backup · POST /keys/restore | opaque backup blob (all versions) → restore into an empty name |
GET | PUT /keys/{name}/rotationpolicy | rotation policy — and it acts: a Rotate trigger’s timeAfterCreate rotates lazily on the emulator clock; attributes.expiryTime sets the new version’s exp |
POST /keys/{name}/rotate | on-demand rotation: a new version with fresh material of the same type/size; key_ops/tags carry over |
POST /keys/{name}/{version}/release | Secure Key Release → {value} (a signed JWS carrying the released public JWK). Only a key created attributes.exportable: true releases, as real KV enforces; release_policy is stored and echoed |
GET/DELETE /deletedkeys/{name}, GET /deletedkeys, POST /deletedkeys/{name}/recover | deleted-key lifecycle |
POST /rng | {count} (1–128) → {value} cryptographically-random base64url bytes |
Release exercises the SDK’s ReleaseKey path. The response value is a
genuine three-part JWS — a fresh signing key is generated per call and its
public JWK rides in the header, so the token self-verifies. Real HSM/enclave
attestation is out of scope (there is no secure enclave to attest), so any
enabled key is releasable; the emulator emulates the shape and call path, not
a hardware trust boundary.
Import reconstructs a real key from the JWK’s private members (RSA
n/e/d/p/q, EC crv/x/y/d); the material is validated (RSA CRT check, EC
on-curve check) and a subsequent sign verifies against the returned public
JWK — the same interop guarantee as generated keys.
Cryptographic operations
Section titled “Cryptographic operations”Versioned and unversioned; wire values are base64url. The caller hashes (Key Vault signs a digest), matching AKV semantics.
| Method + path | Algorithms |
|---|---|
POST /keys/{name}/{version}/sign | /verify | RS256/384/512, PS256/384/512, ES256/384/512 |
POST /keys/{name}/{version}/encrypt | /decrypt | RSA1_5, RSA-OAEP, RSA-OAEP-256 |
POST /keys/{name}/{version}/wrapKey | /unwrapKey | RSA-OAEP, RSA-OAEP-256, RSA1_5 |
key_ops is enforced: an operation outside the key’s list returns
403 Forbidden, and because the returned JWK carries the same key_ops,
SDKs that run public-key operations locally refuse them client-side too.
nbf/exp are enforced for cryptographic use as well — an expired or
not-yet-valid key refuses crypto (403) on the emulator clock, while plain
reads stay permissive, exactly as real Key Vault behaves.
Supported key types
Section titled “Supported key types”- RSA — key sizes 2048 / 3072 / 4096.
- EC — curves P-256 / P-384 / P-521.
RSA-HSM / EC-HSM kty values are accepted and normalized to their
software equivalents (there is no HSM). oct / oct-HSM are refused with
the real error — vaults hold RSA/EC keys only; symmetric keys (and their AES
algorithms) require Managed HSM, which is out of scope. The private key
never leaves the store; every response derives the public JWK (n/e for
RSA, crv/x/y for EC).
The interop guarantee
Section titled “The interop guarantee”A signature the emulator produces verifies against the public JWK it returned —
proven both through the SDK’s Verify and by independent reconstruction of the
public key in the CI e2e (RSA via n/e, EC via the raw r‖s encoding Azure
emits). A tampered signature fails; a disabled key 403s on crypto ops.
SDK example (Go)
Section titled “SDK example (Go)”kc, _ := azkeys.NewClient(vaultURL, cred, opts)key, _ := kc.CreateKey(ctx, "signer", azkeys.CreateKeyParameters{ Kty: to.Ptr(azkeys.KeyTypeRSA), KeySize: to.Ptr(int32(2048)),}, nil)
digest := sha256.Sum256([]byte("attest me"))sig, _ := kc.Sign(ctx, "signer", "", azkeys.SignParameters{ Algorithm: to.Ptr(azkeys.SignatureAlgorithmRS256), Value: digest[:],}, nil)
// Verifies through the SDK — and locally against key.Key (n, e).ok, _ := kc.Verify(ctx, "signer", "", azkeys.VerifyParameters{ Algorithm: to.Ptr(azkeys.SignatureAlgorithmRS256), Digest: digest[:], Signature: sig.Result,}, nil) // *ok.Value == trueVerified end to end against the real azkeys SDK in CI.