Skip to content

feat(contrib/keyvault): add Azure Key Vault TokenStore#83

Open
sergiopalacio wants to merge 2 commits intomasterfrom
feat/keyvault-plugin
Open

feat(contrib/keyvault): add Azure Key Vault TokenStore#83
sergiopalacio wants to merge 2 commits intomasterfrom
feat/keyvault-plugin

Conversation

@sergiopalacio
Copy link
Copy Markdown
Contributor

@sergiopalacio sergiopalacio commented Apr 21, 2026

Summary

Adds microsoft.TokenStore backed by Azure Key Vault as a sibling to the existing FileStore. Distributors using Microsoft SAM can now persist MRRT refresh tokens in a vault instead of (or alongside) local disk.

  • New submodule plugins/contrib/microsoft/keyvault/ with its own go.mod so the Azure SDK does not leak into the default chaperone binary or any contrib consumer that uses only FileStore/oauth/mux. Verified: go tool nm on the compiled binary finds 0 Azure symbols.
  • Secret naming: {prefix}{hex(sha256(tenantID))}. Key Vault secret names forbid dots, and a naive dot-to-hyphen mapping collides (my-a.b vs my.a-b). SHA-256 guarantees collision safety and a valid-alphabet output. The original tenantID is preserved on a tenantID tag for operator visibility; secrets are also tagged managedBy=chaperone.
  • Credential-agnostic: the distributor passes in any azcore.TokenCredential (Default / Managed Identity / Workload Identity / Client Secret). No credential-type flags in keyvault.Config.
  • Error mapping: SecretNotFound (HTTP 404 + specific ErrorCode) maps to contrib.ErrTenantNotFound; all other failures propagate wrapped.
  • Onboarding CLI is unchanged — operators pipe chaperone-onboard microsoft stdout into az keyvault secret set using the same SHA-256 hex encoding. Recipe added to docs/guides/onboarding-refresh-tokens.md.

Verification

Check Result
make build Pass; default binary has zero Azure symbols
make lint (all 4 modules) 0 issues
make vet Pass
make test-race Pass
Coverage on new code 97.9%
gosec on keyvault submodule 0 issues (229 LOC)
govulncheck on keyvault submodule No known vulnerabilities
go test -race -count=10 Pass (concurrent Save/Load stress)

Code review via go-reviewer agent: passed, both Priority B findings (unused logger infra, pointer-identity logger tests) addressed.

Commits

  1. feat(contrib/keyvault): add Azure Key Vault TokenStore — submodule, tests, docs, workspace wiring.
  2. chore(make): include keyvault submodule in multi-module targets — so test, test-race, test-cover, lint, lint-fix, fmt, vet, tidy actually walk into the new module.

Test plan

  • CI green on feat/keyvault-plugin
  • Manual: resolve imports of plugins/contrib/microsoft/keyvault in an IDE
  • Manual: follow the onboarding recipe against a test Azure Key Vault and confirm the proxy reads the seeded token on first request for that tenant
  • Manual: confirm the documented RBAC (Secrets User + Secrets Officer, or get + set access policy) matches what's actually needed

Out of scope

  • No changes to cmd/chaperone-onboard — a dedicated Key Vault subcommand would be a follow-up.
  • No store-level caching — RefreshTokenSource already caches access tokens; re-caching refresh tokens here would duplicate state.
  • No Managed HSM support — only standard Key Vault vaults tested.
  • gosec / govulncheck targets do not scan the new submodule, because they also don't scan plugins/contrib. Adding both together would be a separate follow-up.

Related

  • Existing contract: plugins/contrib/microsoft/store.go
  • Pattern source: plugins/contrib/microsoft/filestore.go

Implements microsoft.TokenStore backed by Azure Key Vault, so distributors
can persist MS SAM refresh tokens in the vault instead of local disk.

Lives in a separate submodule (plugins/contrib/microsoft/keyvault) so the
Azure SDK does not leak into the default chaperone binary or existing
contrib consumers. Secret names are SHA-256 hex of the tenantID (Key Vault
names forbid dots; a naive dot-to-hyphen mapping collides), with the
original tenantID preserved as a tag for operator visibility. Distributors
supply an azcore.TokenCredential of their choice.

The onboarding CLI is unchanged -- operators pipe its stdout into
az keyvault secret set using the same SHA-256 hex encoding, documented in
the onboarding guide.
The test, test-race, test-cover, lint, lint-fix, fmt, vet, and tidy
targets iterate over each module explicitly -- add
plugins/contrib/microsoft/keyvault so CI actually picks it up. gosec and
govulncheck left unchanged: neither currently covers plugins/contrib
either, so adding only keyvault would be inconsistent.
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants