Skip to content

feat(auth): kid-based JWT key rotation support - #60

Merged
PenguinzTech merged 1 commit into
v2.1.xfrom
feature/jwt-kid-rotation
Jul 27, 2026
Merged

feat(auth): kid-based JWT key rotation support#60
PenguinzTech merged 1 commit into
v2.1.xfrom
feature/jwt-kid-rotation

Conversation

@PenguinzTech

@PenguinzTech PenguinzTech commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Adds kid (key ID) headers to every asymmetric JWT the manager issues and multi-key support (JWT_PUBLIC_KEYS_DIR) to all four verifier surfaces (dns-server, dhcp-server, ntp-server, manager). kid = truncated SHA-256 of the public key SPKI, derived — no config. Kid match wins; kid-less tokens try all loaded keys (overlap compat); zero keys fails closed. Rotation runbook added to docs/ENTERPRISE_SECURITY.md.

Tests: 69 green across manager/dns/dhcp (8 new kid tests + 5 rotation tests).
Merge order: merge this before the other auth branches (NHI/MFA/audit build on the same issuance path).

Stack note: bases on chore/dedup-reusable-code (top of the #53#59 chain); auto-retargets toward v2.1.x as the stack merges bottom-up.

🤖 Generated with Claude Code

Summary by Sourcery

Introduce kid-based JWT key rotation across manager and all verifier services, enabling multi-key overlap and fail-closed verification behavior.

New Features:

  • Add kid headers to all manager-issued JWTs for access and client-config domain tokens.
  • Support multi-key JWT verification via JWT_PUBLIC_KEYS_DIR across DNS, DHCP, and NTP servers, with backward compatibility for kid-less tokens.

Enhancements:

  • Refine verifier JWT handling to select keys by kid, try all keys for legacy tokens, and fail closed when keys are missing or unknown.
  • Centralize cryptographic utilities for computing kid from public/private PEM keys in manager, DNS, and DHCP components.

Documentation:

  • Extend enterprise security documentation with a kid-based JWT key rotation runbook and configuration for multi-key public key directories.

Tests:

  • Add unit and integration tests covering kid computation, header presence, key selection, backward compatibility, and fail-closed behavior in manager and DNS/DHCP JWT verification.

Add 'kid' (key ID) header to all asymmetric JWTs to enable graceful key rotation
without flag-day cutoffs. The kid is computed as the first 16 hex characters of
SHA-256 over the public key's DER-encoded SubjectPublicKeyInfo, making it
deterministic and independent of key format.

Issuance (manager):
- AuthService.create_access_token() and create_refresh_token() now include kid
  header computed from the signing private key
- ClientConfigManager._generate_domain_jwt() includes kid header for domain tokens
- Adds compute_kid_from_private_pem() and compute_kid_from_public_pem() helpers

Verification (dns-server/dhcp-server/ntp-server):
- verify_squawk_jwt() and verify_token() support kid-based key selection
- Load multiple public keys from directory (JWT_PUBLIC_KEYS_DIR) or env
- Token with kid: match to loaded key by computed kid, reject if unknown (fail-closed)
- Token without kid: try all loaded keys (backward compat during rotation)
- Single key fallback: JWT_PUBLIC_KEY still works for non-rotating deployments

Configuration:
- New JWT_PUBLIC_KEYS_DIR env var on verifiers to load rotation key set
- Existing JWT_PUBLIC_KEY env/file continues to work (backward compat)

Tests:
- Manager: test_jwt_kid_rotation.py covers kid computation, determinism, and JWT issuance
- DNS: TestKidBasedKeyRotation covers kid selection, unknown kid rejection,
  backward compat with kid-less tokens, and fail-closed behavior
- All existing tests pass (JWT signing/verification unchanged, kid is transparent)

Documentation:
- Add key rotation runbook to ENTERPRISE_SECURITY.md explaining overlap window
  and zero-downtime rotation steps
- Document JWT_PUBLIC_KEYS_DIR configuration

Rotation flow: distribute new public key → wait for propagation → switch manager
signing key → monitor for old-key rejections → retire old key after TTL. Tokens
without kid remain verifiable throughout rotation for 100% compatibility.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PenguinzTech PenguinzTech self-assigned this Jul 25, 2026
@sourcery-ai

sourcery-ai Bot commented Jul 25, 2026

Copy link
Copy Markdown

🧙 Sourcery is reviewing your pull request!


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @PenguinzTech, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@PenguinzTech
PenguinzTech changed the base branch from chore/dedup-reusable-code to v2.1.x July 27, 2026 00:54
@PenguinzTech
PenguinzTech merged commit 992027a into v2.1.x Jul 27, 2026
4 checks passed
@PenguinzTech
PenguinzTech deleted the feature/jwt-kid-rotation branch July 27, 2026 00:57
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.

1 participant