Skip to Content
Trust-Root Channels

Three Trust-Root Channels

A signed Keel artifact is only as verifiable as your ability to obtain the right public key. If the only place to fetch the verification keys is Keel’s own infrastructure, then “verify independently of Keel” is a half-truth — you still depend on Keel being reachable.

Keel publishes its verification key manifest through three independent channels. Verifiers can use any one of them. Each channel is operated by a different party, so a failure in one does not cascade into the others.

1. The three channels

#ChannelWhat you fetchOperator
1Keel APIGET https://api.keelapi.com/v1/compliance/keysKeel
2PyPI wheelpip install keel-verifier ships keel_verifier/data/trust_root.jsonPython Software Foundation infrastructure
3GitHub repositorykeelapi/keel-verifier mirrors the same trust rootGitHub (Microsoft)

All three channels publish the same manifest content — the active and retired Ed25519 public keys, with valid_from / valid_to windows per key, segmented by purpose (export_signing, integrity_checkpoint, permit_binding_signing). When key rotation occurs, all three channels are updated; bundled wheels and the GitHub mirror are regenerated as part of the release process.

2. What works if X disappears

The matrix below captures what a verifier can still do under each independent failure scenario. “Past artifacts” means signed exports, checkpoints, and closure records you’ve already received; “fresh artifacts” means new ones you’d need to fetch from Keel.

Failure scenarioVerify past artifactsFetch fresh checkpointsFetch fresh chain entries
Keel-the-company disappears✓ — keys from PyPI wheel and/or GitHub✓ — checkpoint files on R2 (Cloudflare-operated) remain readable✗ — chain entries require Keel API
Cloudflare/R2 disappears✗ — checkpoint URLs become unreachable✓ — Keel API still serves chain entries
PyPI disappears✓ — keys from GitHub or Keel API
GitHub disappears✓ — keys from PyPI or Keel API
Keel + Cloudflare both disappear✓ — keys from PyPI or GitHub; verify locally cached past artifacts
Keel + PyPI + GitHub all disappear✓ — only with locally cached wheel containing prior trust root

The pattern: verifying past artifacts you already hold is preserved across every single-channel failure. That is the cryptographic floor. Fetching new evidence requires at least one operational channel; that is an operational dependency, not a cryptographic one.

3. How the verifier chooses

The standalone keel-verifier resolves the trust root in this order:

  1. Explicit pin--expected-public-key <ed25519:...> is checked first. Use this when your audit policy requires a pinned key, e.g., a key fingerprint recorded in a contract.
  2. Explicit manifest--key-manifest <path> (local file) or --key-manifest-url <url> (live fetch). Use this for offline audits where you’ve preserved a manifest snapshot alongside the export.
  3. Cached manifest~/.keel-verifier/trust-root.json (when present and not stale). Populated by keel-verify refresh-keys. Useful between key rotations.
  4. Bundled trust rootkeel_verifier/data/trust_root.json shipped with the wheel. The always-present floor. No network access required.

When no flag is passed, the verifier walks 1 → 2 → 3 → 4 and uses the first source that resolves. This is what makes keel-verify export ... work offline out of the box.

4. The bundled-keys snapshot is the disconnected-machine guarantee

The PyPI wheel ships a snapshot of the trust root taken at wheel build time. That snapshot is sufficient to verify any Keel artifact that was signed with a key included in the snapshot, without any network access.

# On a disconnected machine — no network needed pip install keel-verifier # done before going offline keel-verify export --export-file my-export.jsonl.gz --manifest my-manifest.json

The bundled snapshot is stamped with a generation timestamp inside trust_root.json. Customers performing forensic verification five years from now can preserve a wheel of the verifier alongside their archived exports; the verification still works.

5. Limitations: post-rotation freshness

The bundled snapshot has one limitation: once Keel rotates its signing key, a wheel published before the rotation cannot verify artifacts signed with the new key out of the box. The new key is added to the bundled trust_root.json only when a new wheel is published.

Three resolutions:

  • Upgrade the wheel. pip install --upgrade keel-verifier pulls the latest bundled snapshot. Standard practice for routine rotation.
  • Refresh the cached manifest. keel-verify refresh-keys pulls the latest manifest from any channel and writes it to ~/.keel-verifier/trust-root.json. The verifier then prefers the cache over the bundled snapshot. Use this when you can’t easily upgrade the wheel.
  • Pin a manifest at audit time. When you receive a signed artifact, also fetch the current manifest from https://api.keelapi.com/v1/compliance/keys and archive both alongside the artifact. Future verification uses --key-manifest <archived-file>. This is the most defensive practice for long-retention audits.

For routine rotation, see Key Rotation and Active Windows. The manifest carries valid_from and valid_to per key, so retired keys remain in the manifest indefinitely and historical artifacts remain verifiable.

6. Why three channels matters

The “survives the vendor” property — that Keel evidence remains verifiable even if Keel-the-company goes away — is only as strong as the operational channels for fetching keys. One channel makes the property contingent on a single party. Three channels means a verifier can complete its work even if any two of those parties become unreachable.

The three channels are also independent in failure modes:

  • Keel API depends on Keel’s runtime infrastructure (AWS / Cloudflare front).
  • PyPI depends on the Python Software Foundation’s package distribution.
  • GitHub depends on Microsoft / GitHub’s source hosting.

A simultaneous outage of all three would require an extraordinarily correlated failure (or coordinated takedown across three independent organizations). Such a scenario is outside the threat model this document addresses, but in that scenario, verifiers with a previously-cached or wheel-bundled trust root still verify all artifacts signed with keys that were active at the time of caching.

Last updated on Edit this page on GitHub