Files
Fenris/docs/install/signing-key-ceremony.md
T
xavierkandCommandCodeBot d8fa6df072 signing: rpm payload signing, key publication, consumer repo setup for #51
Implement the signing and consumer-repo trust infrastructure:

- Makefile: add generate-test-key, sign-rpm, checksums, clearsign targets;
  make release now automates the full build→sign→checksum→clearsign flow
- Key ceremony: document the import→sign→delete lifecycle, key rotation
  outline, and private-key-in-password-manager policy
- Public key: update placeholder with raw URL, algorithm, and ceremony ref
- Consumer docs: README now covers apt signed-by keyring flow, dnf repo
  file setup, signature verification commands, and migration runbook link
- Release spec: updated to reference ceremony doc and rpmsign workflow
- Tests: 36 structural signing tests (nfpm config, Makefile targets,
  repo file, key publication, ceremony doc, consumer docs, spec refs)
  plus throwaway-key RPM signature and clearsign mechanics; no network
  or real key required

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-03 14:14:55 +05:30

4.0 KiB

Signing key ceremony

The Fenris packaging key signs RPM payloads and clearsigns SHA256SUMS manifests. This document describes the key's lifecycle: creation, per-release use, rotation, and destruction.

Key specification

Property Value
Algorithm RSA 3072
UID Fenris Packaging <packaging@bongbetic.com>
Expiry 2 years from creation
Hierarchy Single key — no master/subkey split (single maintainer, manual builds)
Private key storage Password manager only
Public key storage packaging/keys/fenris-packaging.asc in-repo, release notes, docs
Keyservers Never — TOFU-over-TLS via raw URL

First release: key creation

# Generate the dedicated RSA-3072 packaging key
gpg --batch --gen-key <<EOF
%no-protection
Key-Type: RSA
Key-Length: 3072
Name-Real: Fenris Packaging
Name-Email: packaging@bongbetic.com
Expire-Date: 2y
%commit
EOF

# Export the public half — this file is committed to the repo
gpg --armor --export packaging@bongbetic.com > packaging/keys/fenris-packaging.asc

# Print the fingerprint for docs and release notes
gpg --fingerprint packaging@bongbetic.com

Save the private key to the password manager immediately:

gpg --armor --export-secret-keys packaging@bongbetic.com

Then delete the private key from the local keyring — it must never persist on any build host:

gpg --delete-secret-keys packaging@bongbetic.com
gpg --delete-keys packaging@bongbetic.com

The committed fenris-packaging.asc must contain the real public key (replace the placeholder comments).

Per-release signing flow

Each release performs: import → sign → delete. The private key is never stored on disk longer than the release takes.

Step 1: Import the private key

Retrieve the private key from the password manager and import it:

gpg --import /tmp/packaging-key-private.asc
rm /f /tmp/packaging-key-private.asc   # Shred if possible

Step 2: Build and sign packages

The Makefile target make release handles signing automatically when the key is in the keyring:

make release    # builds, signs RPM, clearsigns SHA256SUMS, prints upload steps

Under the hood:

  1. nfpm pkg -p rpm signs the RPM payload via rpm.signature.key_file and rpm.signature.key_id in packaging/nfpm.yaml.
  2. sha256sum generates the checksum manifest.
  3. gpg --clearsign produces SHA256SUMS.asc with the packaging key.

Step 3: Delete the private key

Immediately after signing:

gpg --delete-secret-keys packaging@bongbetic.com
gpg --delete-keys packaging@bongbetic.com

Verify the key is gone:

gpg --list-keys packaging@bongbetic.com
# Should produce: gpg: keyblock resource ...: No such file or directory

The entire import → sign → delete cycle should take minutes. The private key must never be left in any keyring between releases.

Key rotation (outline)

When the key approaches expiry, or if it is compromised:

  1. Generate a new key using the same procedure as first release.
  2. Publish the new public key alongside the old one in-repo:
    packaging/keys/fenris-packaging.asc          # new key (primary)
    packaging/keys/fenris-packaging-previous.asc  # old key (one cycle)
    
  3. Sign the next RPM with the new key.
  4. Update fenris.repo to list both gpgkey URLs (dnf accepts multiple):
    gpgkey=https://git.bongbetic.com/xavierk/Fenris/raw/branch/main/packaging/keys/fenris-packaging.asc
          https://git.bongbetic.com/xavierk/Fenris/raw/branch/main/packaging/keys/fenris-packaging-previous.asc
    
  5. Drop the old key from the repo after one release cycle. Delete fenris-packaging-previous.asc and revert gpgkey to the single URL.

Verification

Consumers verify the RPM payload signature via dnf (gpgcheck=1 in fenris.repo points at the published public key). The SHA256SUMS manifest verification is manual for downloaded assets:

gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS