kms/azure: fix encrypt/decrypt round trip for Azure Key Vault (#11692)

* kms/azure: fix encrypt/decrypt round trip for Azure Key Vault

The provider stored the wrapped data key as string(encryptResult.Result)
in the JSON envelope, sent the encryption context as AAD to an RSA-OAEP
key, and passed a full key URL to the azkeys client in the name
position. Each of those breaks a round trip on its own.

- split the key URL into the (name, version) pair azkeys expects before
  Encrypt, Decrypt and GetKey; a plain name still resolves to the latest
  version, and decrypt keeps the stored version so objects stay readable
  after a key rotation
- store the wrapped key base64-encoded and decode it strictly, so the JSON
  envelope no longer replaces the raw bytes with U+FFFD
- stop sending AAD: Key Vault rejects it on RSA-OAEP with BadParameter,
  so the encryption context is logged and dropped instead

* kms/azure: reject a key URL that names another vault

splitKeyID dropped the host of a full Key Vault URL, so a key ID from a
different vault silently resolved to this vault's same-named key. Return
an error instead of encrypting under a key the caller did not ask for.

* kms/azure: bind encryption context via an envelope digest

RSA-OAEP rejects AAD, so removing it left the encryption context
unauthenticated: a wrapped key could be decrypted under a different
object's context. Record a sha256 digest of the marshaled context in
the envelope's provider_specific field on encrypt and verify it before
calling Decrypt, restoring the binding without AAD.

* kms/azure: treat an explicit :443 port as the same vault

* kms/azure: accept an absent context digest only for empty contexts

* kms/azure: normalize both hosts when comparing key URLs to the vault

splitKeyID stripped :443 and a trailing dot from the configured vault but
only :443 from the key URL, so a key URL naming the same vault with a
trailing DNS dot was rejected before Azure was ever called. Compare both
sides through vaultHost so they are normalized identically.

* kms/azure: reject non-key vault URLs in splitKeyID, document digest limits

A Key Vault URL that does not name a key under /keys/, has an empty key
name, or carries extra path segments now fails fast instead of being
passed to the client as a key name, where it would surface as a
confusing vault-side error.

Also note that the envelope context digest is a client-side mismatch
check, not vault-authenticated AAD, and only allocate providerSpecific
when a context is present.

* ci: compile and test azurekms-gated code

weed/kms/azure is excluded from every default build, so nothing in CI
compiled it; that is how the provider shipped unregistered. Build the
tree and run the kms tests with -tags azurekms on every Go change.

---------

Co-authored-by: Yi-111-a <>
Co-authored-by: Chris Lu <chrislusf@users.noreply.github.com>
Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-10 23:40:19 +08:00
1 parent b2eefb8a73
commit c96eb7b8ee
3 files changed
+503 -22

No files matched your search

+18
View File
@@ -148,3 +148,21 @@ jobs:
# -short skips the e2e suites already covered on amd64.
- name: Test linux/386
run: cd weed; GOOS=linux GOARCH=386 go test -short ./...
build-azurekms:
name: Build and test with azurekms tag
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
# weed/kms/azure is excluded from every default build, so without this
# nothing compiles it and tag-gated code silently rots.
- name: Build and test with azurekms
run: |
cd weed
go build -tags azurekms ./...
go test -tags azurekms ./kms/...