Skip to Content
Key Rotation Windows

Key Rotation and Active Windows

Keel rotates signing keys without invalidating historical exports. You verify old artifacts with the key that was active when the artifact was signed, not necessarily the key that is active today.

How Keel handles signing-key rotation transparently

Each signed artifact carries enough metadata for the verifier to resolve the correct public key:

  • exports carry signing metadata in the export manifest;
  • checkpoints carry signing metadata in the checkpoint record;
  • closure records carry their binding signing metadata in the bundled chain entry payload;
  • the public key manifest retains active and retired verification keys.

Active keys sign new artifacts. Retired keys do not sign new artifacts, but they remain in the manifest so historical artifacts keep verifying. A retired key is normal rotation history. It is not the same thing as a compromised key.

What the public manifest endpoint contains

Fetch the public key manifest from:

GET /v1/compliance/keys

The manifest is a JSON object with a keys list. Each entry identifies a retained verification key.

{ "keys": [ { "key_id": "export-2026-annual", "purpose": "export_signing", "public_key": "ed25519:BASE64_PUBLIC_KEY...", "status": "active", "valid_from": "2026-01-01T00:00:00Z", "valid_to": null }, { "key_id": "export-2025-annual", "purpose": "export_signing", "public_key": "ed25519:BASE64_PUBLIC_KEY...", "status": "retired", "valid_from": "2025-01-01T00:00:00Z", "valid_to": "2026-01-01T00:00:00Z" } ] }

The JSON fields are valid_from and valid_to. Operationally, they are the key’s active-from and active-to window.

The purpose field prevents using the wrong class of key. Export signatures, integrity checkpoints, and permit closure bindings use distinct purposes.

How the verifier resolves old vs new keys

The verifier resolves keys conservatively.

If the artifact has a key_id, the verifier looks for the manifest entry with the matching key_id and matching purpose.

If the artifact is legacy and has no key_id, the verifier uses the artifact’s signing time and the manifest’s valid_from / valid_to windows. Exactly one key for the right purpose must cover that signing time.

If no key covers the signing time, verification fails. If multiple keys cover the signing time, verification fails. The verifier does not guess.

Use the manifest whenever possible:

keel-verify export \ --export-file bundle.json \ --manifest export-manifest.json \ --key-manifest-url https://api.keelapi.com/v1/compliance/keys \ --walk-events \ --verify-closure

For offline audit files, download the manifest once and preserve it with the export.

keel-verify export \ --export-file bundle.json \ --manifest export-manifest.json \ --key-manifest public-key-manifest.json \ --walk-events \ --verify-closure

Expected rotation cadence

Expect routine signing-key rotation at least annually unless your contract or deployment profile specifies a shorter cadence.

Annual rotation means:

  • a new active key signs new artifacts after the rotation timestamp;
  • the previous key becomes retired with a closed valid_to;
  • historical exports remain verifiable because the retired public key stays in the manifest;
  • auditors should preserve the manifest used at verification time with their audit files.

What to do if a key compromise is suspected

A suspected compromised key is not routine rotation.

If you suspect compromise:

  1. Stop treating affected signatures as sufficient evidence for the suspected compromise window.
  2. Preserve the public key manifest you used, the export bundle, the export manifest, verifier output, and file hashes.
  3. Contact your Keel admin and security@keelapi.com immediately.
  4. Request the rotation record, the suspected exposure window, and a fresh public key manifest after rotation.
  5. Re-run verification for artifacts before, during, and after the suspected window.
  6. Request an incident-scoped export and bracket checkpoints around the suspected window.

Do not treat a compromised key as merely retired. A retired key is still trusted for the window when it was active. A compromised key may require narrowing or rejecting trust for part of that window, depending on the investigation.

Last updated on Edit this page on GitHub