Skip to content

Sign Your Repository

Sign RPM and APT metadata, optionally sign RPM packages, and enable client verification.

SOW has two independent signing paths:

Path Output Client control
RPM metadata repodata/repomd.xml.asc repo_gpgcheck=1
APT metadata InRelease and Release.gpg Signed-By
RPM package body embedded RPM signature gpgcheck=1

APT trusts package hashes through the signed Release; SOW does not re-sign DEB package bodies. Start with metadata signing. Add RPM package signing only when you own the signing policy for those package bytes.

1. Create a dedicated key

The commands below create an unencrypted example key. Use a protected key and a passphrase reference for production; see the configuration reference.

SIGNING_UID='SOW Repository <[email protected]>'
gpg --batch --pinentry-mode loopback --passphrase '' \
  --quick-generate-key "$SIGNING_UID" rsa3072 sign 2y

FPR="$(gpg --batch --with-colons --list-secret-keys "$SIGNING_UID" \
  | awk -F: '$1 == "fpr" {print $10; exit}')"
test -n "$FPR"

sudo install -d -m 0700 /srv/sow-secrets
sudo chown "$(id -u):$(id -g)" /srv/sow-secrets
gpg --batch --pinentry-mode loopback --passphrase '' --armor \
  --export-secret-keys "$FPR" > /srv/sow-secrets/repo-signing.asc
gpg --armor --export "$FPR" > /srv/sow-secrets/repo-signing.pub
chmod 600 /srv/sow-secrets/repo-signing.asc

Keep the secret key outside the Workspace’s public Repository tree and outside every web root. If a dedicated service account runs SOW, make that account—not the interactive user—the directory owner. Distribute only repo-signing.pub to clients.

2. Configure metadata signing

In /srv/sow/sow.yml, add the relevant blocks under the Repository. Omit the ecosystem you do not use:

repos:
  pigsty:
    signing:
      rpm:
        metadata:
          key: file:///srv/sow-secrets/repo-signing.asc
      deb:
        metadata:
          key: file:///srv/sow-secrets/repo-signing.asc
    dists:
      # existing Dist definitions remain here

Validate the key reference, rebuild, and run the publication gate:

cd /srv/sow
sow config check
sow build -r pigsty
sow check -r pigsty

For a protected key, add passphrase: env://SOW_METADATA_PASSPHRASE or a bounded file reference next to key. SOW never writes key or passphrase material into configuration, SQLite, JSON, or logs.

3. Verify metadata manually

Use the exact paths for your Dists and architectures:

gpg --verify \
  pigsty/dists/el9/x86_64/repodata/repomd.xml.asc \
  pigsty/dists/el9/x86_64/repodata/repomd.xml

gpg --verify pigsty/dists/trixie/InRelease
gpg --verify \
  pigsty/dists/trixie/Release.gpg \
  pigsty/dists/trixie/Release

sow check verifies the configured signing identity as part of its deeper consistency checks. Manual verification is still useful when establishing a client trust root.

4. Optional: sign RPM package bodies

Add rpm.packages only if clients require embedded package signatures:

repos:
  pigsty:
    signing:
      rpm:
        packages:
          mode: fill
          key: agent://REPLACE_WITH_THE_FINGERPRINT
        metadata:
          key: file:///srv/sow-secrets/repo-signing.asc

Replace the placeholder with the 40-hex fingerprint printed in $FPR. For this operation:

  • rpm and gpg must be installed;
  • the matching secret key must be available in the ambient GPG environment used by rpm;
  • fill preserves packages already signed by the configured or trusted_keys identities;
  • always re-signs everything not already signed by the configured identity;
  • never leaves input bytes unchanged.

SOW invokes rpm --addsign or rpm --resign on a private staged copy, not on the input file. Revalidate and rebuild after changing the policy:

sow config check
sow build -r pigsty
sow check -r pigsty

Inspect a resulting package with rpmkeys --checksig /path/to/package.rpm.

5. Enable dnf verification

Transfer the public key to the client through a trusted channel:

sudo install -m 0644 /path/to/repo-signing.pub /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty

Then enable the checks that correspond to what you signed:

[pigsty-el9]
name=Pigsty EL9
baseurl=https://repo.example.com/pigsty/dists/el9/$basearch/
enabled=1
repo_gpgcheck=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty

Set gpgcheck=0 if package-body signing is not configured. Do not disable repo_gpgcheck after configuring metadata signing.

6. Enable APT verification

Install the public key as a dedicated keyring:

sudo gpg --dearmor --yes \
  --output /usr/share/keyrings/pigsty-archive-keyring.gpg /path/to/repo-signing.pub

Reference it from deb822 configuration and do not set Trusted: yes:

Types: deb
URIs: https://repo.example.com/pigsty
Suites: trixie
Components: main
Architectures: amd64
Signed-By: /usr/share/keyrings/pigsty-archive-keyring.gpg

Run apt update and treat any signature error as a failed deployment, not as a reason to weaken the client configuration.

Plain-mode RPM signing

Plain mode can sign RPM package bodies, but it does not sign repository metadata or create an APT Release:

sow create /srv/flat --sign-with 0123456789ABCDEF

The key must be exactly 16, 40, or 64 hexadecimal characters, with no 0x prefix, and the matching private key must be usable by the ambient rpm/GPG setup. Without --overwrite, already signed RPMs keep their bytes; adding --overwrite explicitly re-signs every RPM. SOW signs private staged copies before replacing package bytes and metadata.

Key changes

Changing a key reference or resolved fingerprint marks affected Dists dirty. A metadata key can be changed by distributing the new public key, rebuilding, checking, and then switching client enforcement. RPM package keys need a staged rollover: Package Objects are immutable, and build rejects stored RPMs that do not satisfy the new policy instead of re-signing them in place. Use fill with the old public key in trusted_keys until old package coordinates have been withdrawn or replaced. Finish with a real client acceptance test in the target environment.

Run the final signed repository through the exact dnf/APT versions and trust policy used in production. The automated scope is listed under Platforms & Integrations.