Skip to content

security(apt): sign the published APT repository - #35

Merged
vietanhdev merged 1 commit into
mainfrom
security/sign-apt-repository
Jul 20, 2026
Merged

security(apt): sign the published APT repository#35
vietanhdev merged 1 commit into
mainfrom
security/sign-apt-repository

Conversation

@vietanhdev

Copy link
Copy Markdown
Owner

The problem

The APT repo at gh.vietanh.dev/ThinkUtils/apt publishes Release, Packages, and Packages.gz — but no InRelease and no Release.gpg. It is entirely unsigned, which is why the install instructions need [trusted=yes], a flag that disables apt's signature checking outright.

$ curl -o /dev/null -w '%{http_code}' .../Release       # 200
$ curl -o /dev/null -w '%{http_code}' .../InRelease      # 404
$ curl -o /dev/null -w '%{http_code}' .../Release.gpg    # 404

That matters more here than for a typical repo: this package installs a root-invoked fan helper plus a polkit rule, and dpkg maintainer scripts run as root. HTTPS authenticates the host for the duration of the transfer; it says nothing about whether the bytes sitting on gh-pages, or in any cache in front of it, are the ones CI built.

The change

  • Signs Release into InRelease + Release.gpg when APT_GPG_PRIVATE_KEY is configured, and publishes the public half as thinkutils-archive-keyring.asc
  • Generated index.html switches to signed-by= instructions when signed
  • With no key set, publishes unsigned exactly as before but emits a ::warning:: — releases keep working today
  • Deletes any previously published signature when unsigned. A stale InRelease next to a regenerated Release breaks apt update outright, which is worse for users than being unsigned
  • Declares apt-utils: the step calls apt-ftparchive but installed only dpkg-dev, working purely by luck of the runner image preinstalling it

Verification

The step's shell was extracted from the YAML and run against a throwaway key, so the logic under test is the shipped logic, not a paraphrase:

  • signatures verify against the published public key alone (what a user's apt actually does)
  • a tampered Release is rejected
  • removing the key deletes the stale signature files and reverts the index to the trusted=yes form
  • 18/18 checks pass

Action required to actually turn this on

This needs a signing key, which is yours to create — see docs/development/apt-signing.md. Until APT_GPG_PRIVATE_KEY and APT_GPG_PASSPHRASE are set as repo secrets, releases stay unsigned (with a warning). Nothing breaks in the meantime.

The APT repo shipped no InRelease and no Release.gpg, so the install
instructions needed [trusted=yes] -- which tells apt to skip signature
verification entirely. That is worse than average here: the package
installs a root-invoked fan helper plus a polkit rule, and dpkg
maintainer scripts run as root. HTTPS authenticates the host during the
transfer; it says nothing about whether the bytes on gh-pages, or in any
cache in front of it, are the ones CI built.

Signs Release into InRelease and Release.gpg when APT_GPG_PRIVATE_KEY is
configured, publishes the public half, and switches the generated
index.html to signed-by= instructions. With no key set it publishes
unsigned as before but warns -- and deletes any previously published
signature, because a stale InRelease beside a regenerated Release breaks
apt update outright, which is worse for users than unsigned.

Also declares apt-utils: the step calls apt-ftparchive but installed only
dpkg-dev, working by luck of the runner image preinstalling it.

Verified by extracting the step from the YAML and running it against a
throwaway key: signatures verify against the published public key alone,
a tampered Release is rejected, and removing the key deletes the stale
signature files and reverts the index.

docs/development/apt-signing.md covers key generation and the two secrets.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 20, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
thinkutils 27e6064 Jul 20 2026, 02:58 AM

@vietanhdev
vietanhdev merged commit d2a0fb9 into main Jul 20, 2026
9 of 10 checks passed
@vietanhdev
vietanhdev deleted the security/sign-apt-repository branch July 20, 2026 03:09
vietanhdev added a commit that referenced this pull request Jul 20, 2026
The install instructions hand users a flag that disables apt's signature
verification, next to a package that installs a root-invoked helper, with
no indication that either fact is true.

States what the flag does, offers the manual .deb path for anyone not
willing to take that trade, and points at the signing doc. Also adds
apt-signing to the Development sidebar -- it shipped in #35 but was
reachable only by knowing the URL.

These instructions revert to signed-by= automatically once a signing key
is configured; the release workflow generates the page from whichever
form it actually published.
vietanhdev added a commit that referenced this pull request Jul 20, 2026
The install instructions hand users a flag that disables apt's signature
verification, next to a package that installs a root-invoked helper, with
no indication that either fact is true.

States what the flag does, offers the manual .deb path for anyone not
willing to take that trade, and points at the signing doc. Also adds
apt-signing to the Development sidebar -- it shipped in #35 but was
reachable only by knowing the URL.

These instructions revert to signed-by= automatically once a signing key
is configured; the release workflow generates the page from whichever
form it actually published.
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