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>
135 lines
4.0 KiB
Markdown
135 lines
4.0 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
gpg --delete-secret-keys packaging@bongbetic.com
|
|
gpg --delete-keys packaging@bongbetic.com
|
|
```
|
|
|
|
Verify the key is gone:
|
|
|
|
```bash
|
|
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:
|
|
```text
|
|
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):
|
|
```ini
|
|
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:
|
|
|
|
```bash
|
|
gpg --verify SHA256SUMS.asc SHA256SUMS
|
|
sha256sum -c SHA256SUMS
|
|
```
|