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
| # | Channel | What you fetch | Operator |
|---|---|---|---|
| 1 | Keel API | GET https://api.keelapi.com/v1/compliance/keys | Keel |
| 2 | PyPI wheel | pip install keel-verifier ships keel_verifier/data/trust_root.json | Python Software Foundation infrastructure |
| 3 | GitHub repository | keelapi/keel-verifier mirrors the same trust root | GitHub (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 scenario | Verify past artifacts | Fetch fresh checkpoints | Fetch 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:
- 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. - 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. - Cached manifest —
~/.keel-verifier/trust-root.json(when present and not stale). Populated bykeel-verify refresh-keys. Useful between key rotations. - Bundled trust root —
keel_verifier/data/trust_root.jsonshipped 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.jsonThe 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-verifierpulls the latest bundled snapshot. Standard practice for routine rotation. - Refresh the cached manifest.
keel-verify refresh-keyspulls 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/keysand 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.
Related pages
- Key Rotation and Active Windows — how the manifest carries multiple keys with active windows
- Independent Verification Overview — the verifier’s claim and trust boundary
- Running Keel Verify — the CLI walkthrough
- Trust & Integrity — the four-layer integrity model