How to Detect Mirror Tampering with APT, Yum, and DNF Hash-Chain Provenance
Enable end-to-end clearsigned InRelease + repomd.xml.asc verification for OS package mirrors by configuring the trust-root keyring.
Overview
OS-package mirrors (APT, Yum, DNF) have been a blind spot for most
registry-proxy solutions — they’re not SemVer, they’re not on the OSV
malware feed, and they don’t have a SLSA-style attestation standard.
But they do have a hash-chain provenance model that pre-dates SLSA by
a decade: a clearsigned InRelease file (APT) or a detached
repomd.xml.asc (Yum / DNF) at the top of the repo, with each
descendant file hash-chained back up to the signed root.
Chainsaw’s hasProvenance condition now walks that chain end-to-end for
every OS package request:
- APT — PGP-verify
InRelease/Release.gpg, walk the hash ofPackages.{gz,xz}→ hash of the requested.debfile - Yum / DNF — PGP-verify
repomd.xml.asc, walk the hash ofprimary.{xml,sqlite}.{gz,xz}→ hash of the requested.rpmfile
Result.Status reaches StatusVerified only when the chain validates
top to bottom — no silent passes on mirror tampering.
Prerequisites
- Chainsaw admin access to environment configuration
- Access to your organisation’s trusted APT / RPM signing keys
(
.ascor.gpgfiles)
Step 1: Set the Trust Root
The trust root is a file or directory of public keys that Chainsaw treats as authoritative signers for the OS-package repos it proxies. Configure via two environment variables:
# File: a single keyring file (can be .asc-armored or .gpg-binary)
export CHAINSAW_APT_KEYRING=/etc/chainsaw/apt-keyring.asc
export CHAINSAW_RPM_KEYRING=/etc/chainsaw/rpm-keyring.gpg
# Directory: Chainsaw picks up every *.asc and *.gpg file inside
export CHAINSAW_APT_KEYRING=/etc/chainsaw/keys/apt/
export CHAINSAW_RPM_KEYRING=/etc/chainsaw/keys/rpm/
If unset, Chainsaw falls back to an embedded Debian / Fedora keyring snapshot shipped with the binary. The embedded fallback is a safety net for developer setups — production deployments should set the env vars explicitly so the trust root is auditable.
StatusUnavailable with a descriptive error
(“inconclusive: keyring unavailable”) so the policy engine treats the
check as failing rather than passing.Step 2: Create the Provenance Policy
- Navigate to Policies → Create Policy
- Name:
Require provenance — APT / Yum / DNF - Condition:
hasProvenance = true - Scope: APT / Yum / DNF repositories
- Action: Block
Step 3: Verify the Walk
Trigger an install against your proxy from a client:
apt-get install curl # will fetch via Chainsaw
The BOM will show the provenance result for the fetched .deb:
| Field | Value |
|---|---|
provenance.status | verified |
provenance.signer | PGP fingerprint from your trust root |
provenance.chain | InRelease → Packages.gz → curl_X.Y.Z.deb |
For Yum / DNF:
| Field | Value |
|---|---|
provenance.status | verified |
provenance.signer | PGP fingerprint from RPM keyring |
provenance.chain | repomd.xml.asc → primary.xml.gz → curl-X.Y.Z.rpm |
Step 4: Handle the Known Gap — by-hash Layouts
Some repos serve exclusively via the APT by-hash layout (/by-hash/SHA256/...
paths). Chainsaw currently walks the canonical-filename path rather than
the by-hash path. If you proxy a by-hash-only repo, open an issue;
meanwhile the provenance check will return StatusUnavailable with a
“by-hash layout not supported” reason rather than silently passing.
Step 5: Rotate Keys Safely
When an upstream rolls its signing key:
- Add the new key to your keyring file / directory
- Wait until the new key has signed at least one
InRelease/repomd.xmlfor each series you proxy - Remove the old key
Running with both keys in the keyring during the overlap window keeps existing installs working without a provenance-failure outage.
Ecosystem Matrix Reference
For the full provenance matrix (which ecosystems are Sigstore, PGP,
sum.golang.org, hash-chain, or absent), run
chainsaw policy preflight
against your server → the HasProvenance condition.