Skip to content

Only accept OS updates signed by this project's key - #120

Merged
TB516 merged 1 commit into
mainfrom
image-signing
Oct 22, 2026
Merged

TB516 merged 1 commit into
mainfrom
image-signing

Conversation

@TB516

@TB516 TB516 commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Your machine trusts an OS update only because it came from ghcr.io over TLS. That depends on every certificate authority the system trusts, and the eMudhra compromise showed how one bad authority can undermine it. A network attacker with a mis-issued certificate, or anyone who tampers with the registry, could serve a fake update.

The existing publish step now has Podman sign each image as it pushes, using the COSIGN_PRIVATE_KEY secret. A cosign check then fails the build if that key doesn't match the public key shipped in the image. Installed systems require that signature for ghcr.io/tb516/os before bootc accepts an update. Rebasing to other images, such as Bluefin or Dakota, still works as before.

Our policy.json replaces the copy from freedesktop-sdk's containers-common, so the config element now depends on that package and is allowed to replace that one file. If signing fails, the build fails, and installed systems keep their current image. docs/automation.md covers recovery and key rotation.

Tested:

  • In a VM, bootc refused the current unsigned ghcr.io/tb516/os:latest, rejected an unsigned image from a local registry, and accepted one signed with a test key.
  • Podman signed with a cosign-generated key exactly as the publish action does. The image's policy accepted it and rejected an image signed with another key.
  • The push fails if the signature storage setting is missing.
  • The final image builds and passes bootc container lint. Inside it, the policy rejects unsigned ghcr.io/tb516/os and still accepts other images.

Signing first runs on GitHub's runner in the main build after merging. That build still installs on your current system, which accepts any image; updates after that must be signed.

Updates were trusted only because they came from ghcr.io over TLS, which
depends on every certificate authority the system trusts. The publish
step now has Podman sign each image with the COSIGN_PRIVATE_KEY secret,
and a cosign check fails the build if that key doesn't match the public
key shipped in the image. Installed systems require that signature for
ghcr.io/tb516/os before bootc accepts an update. Other images are
unaffected.

The policy replaces containers-common's copy, so the config element now
stages after it.
@TB516
TB516 merged commit 7dcba79 into main Oct 22, 2026
1 check passed
@TB516
TB516 deleted the image-signing branch October 22, 2026 00:11
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