Skip to content

Publish fallback keys in JWKS for rotation - #6464

Open
lorenzozanee wants to merge 2 commits into
stacklok:mainfrom
lorenzozanee:fix/jwks-fallback-rotation
Open

Publish fallback keys in JWKS for rotation#6464
lorenzozanee wants to merge 2 commits into
stacklok:mainfrom
lorenzozanee:fix/jwks-fallback-rotation

Conversation

@lorenzozanee

Copy link
Copy Markdown
Contributor

Summary

The three-step zero-downtime rotation documented in pkg/authserver/server/keys/config.go:31-39 depends on FallbackKeyFiles being published in /.well-known/jwks.json during step 1, so consumers can verify tokens signed with the new key before it becomes the signer. FileProvider correctly loads fallbacks into allKeys and exposes them via PublicKeys(), but server construction only called SigningKey() and built SigningJWKS with a single entry. PublicJWKS() therefore always returned one key, step 1 was a no-op, and promotion became a hard cutover that invalidated outstanding JWTs for up to max-age=3600.

  • Populate SigningJWKS from KeyProvider.PublicKeys() keeping the primary first; fallbacks are added as public-only JWKs
  • Keep SigningKey() as the sole signing source
  • Preserve single-key behavior when no fallbacks are configured

Fixes #6451

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe):

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Verified pkg/authserver/... unit suite passes. Added TestNewAuthorizationServerConfig_WithAdditionalKeys (primary-first ordering, public-key stripping, signing isolation) and TestNewServer_JWKSIncludesFallbackKeys which starts a FileProvider with a fallback file and hits /.well-known/jwks.json to assert both keys are published.

API Compatibility

  • This PR does not break the v1beta1 API, OR the api-break-allowed label is applied and the migration guidance is described above.

Changes

File Change
pkg/authserver/server/provider.go Add AdditionalKeys to AuthorizationServerParams and build SigningJWKS as signing + additional
pkg/authserver/server_impl.go Collect PublicKeys() into AdditionalKeys (dedup primary, public-only, warn on error)
pkg/authserver/server/provider_test.go Add multi-key JWKS test
pkg/authserver/server_test.go Add /.well-known/jwks.json integration test with FileProvider fallback

Does this introduce a user-facing change?

Yes. /.well-known/jwks.json and /.well-known/openid-configuration (id_token_signing_alg_values_supported) now correctly advertise fallback keys and their algorithms during rotation, enabling the documented overlap window. No configuration change required.

The documented three-step rotation relies on FallbackKeyFiles
being advertised in /.well-known/jwks.json before promotion.
Server construction only read SigningKey, so the JWKS always
contained a single key and step 1 had no observable effect.

Populate SigningJWKS from PublicKeys, keeping the primary key
first and publishing fallbacks as public-only JWKs. Signing
still uses only the primary key. This restores the overlap
window and fixes the hard-cutover on promotion.

Signed-off-by: lorenzozanee <wyz0707@proton.me>
@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.03%. Comparing base (0fb54d4) to head (098f7d1).

Files with missing lines Patch % Lines
pkg/authserver/server_impl.go 88.88% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6464   +/-   ##
=======================================
  Coverage   78.02%   78.03%           
=======================================
  Files         767      767           
  Lines       74273    74294   +21     
=======================================
+ Hits        57955    57977   +22     
+ Misses      16313    16312    -1     
  Partials        5        5           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The documented three-step rotation relies on FallbackKeyFiles
being advertised in /.well-known/jwks.json before promotion.
Server construction only read SigningKey, so the JWKS always
contained a single key and step 1 had no observable effect.

Populate SigningJWKS from PublicKeys, keeping the primary key
first and publishing fallbacks as public-only JWKs. Signing
still uses only the primary key. This restores the overlap
window and fixes the hard-cutover on promotion.

Signed-off-by: lorenzozanee <wyz0707@proton.me>
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.

authserver: JWKS endpoint publishes only the signing key, making documented key rotation a hard cutover

1 participant