feat: add GPG key setup script and generalize nginx GPG key serving
All checks were successful
poll-upstream / check (push) Successful in 2s

Add script/setup/gpg.sh to generate a dedicated lair keyring with a
certify-only master key and a 1-year signing subkey, cross-signed by
both personal keys. The public key is synced to oolon as <short-id>.gpg.

Update nginx config to serve any .gpg file instead of a hardcoded
RPM-GPG-KEY-mistralrs path, supporting multiple keys as the repo grows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 14:43:07 +03:00
parent e6c2b4e402
commit 8ceabed354
2 changed files with 100 additions and 1 deletions

View File

@@ -30,7 +30,7 @@ server {
add_header Cache-Control "no-cache, must-revalidate"; add_header Cache-Control "no-cache, must-revalidate";
} }
location = /RPM-GPG-KEY-mistralrs { location ~ \.gpg$ {
default_type text/plain; default_type text/plain;
} }
} }

99
script/setup/gpg.sh Executable file
View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -euo pipefail
keyring_dir="${HOME}/.gnupg/lair"
key_uid="rpm@lair.cafe"
remote_host=oolon
remote_key_dir="/var/www/rpm"
signing_keys=(
"1C09AC24C113C7F080DD4AA5B3C5A958508A43F2"
"CF3E5AA5DAFD4A7FB69053E393977688ACF3510F"
)
# ensure the lair keyring directory exists
install --directory --mode 700 "${keyring_dir}"
# check for an existing valid key in the lair keyring
existing_fpr=$(gpg --homedir "${keyring_dir}" --batch --with-colons --list-keys "${key_uid}" 2>/dev/null \
| awk -F: '/^fpr:/ { print $10; exit }') || true
if [ -n "${existing_fpr}" ]; then
echo "found existing key: ${existing_fpr}"
else
echo "no key found for ${key_uid} in ${keyring_dir}, generating..."
# create a certify-only master key
gpg --homedir "${keyring_dir}" --batch --gen-key <<KEYEOF
%no-protection
Key-Type: eddsa
Key-Curve: ed25519
Key-Usage: cert
Name-Real: lair.cafe RPM signing
Name-Email: ${key_uid}
Expire-Date: 0
%commit
KEYEOF
existing_fpr=$(gpg --homedir "${keyring_dir}" --batch --with-colons --list-keys "${key_uid}" \
| awk -F: '/^fpr:/ { print $10; exit }')
echo "generated master key: ${existing_fpr}"
# add a dedicated signing subkey with 1-year expiry
gpg --homedir "${keyring_dir}" --batch --passphrase '' --quick-add-key \
"${existing_fpr}" ed25519 sign 1y
echo "added signing subkey to ${existing_fpr}"
# sign the lair key with each personal key from the default keyring
gpg --homedir "${keyring_dir}" --batch --armor --export "${existing_fpr}" | gpg --import
for signer in "${signing_keys[@]}"; do
gpg --batch --yes --local-user "${signer}" --sign-key "${existing_fpr}"
echo "signed lair key with ${signer}"
done
gpg --armor --export "${existing_fpr}" | gpg --homedir "${keyring_dir}" --import
echo "imported signatures back into lair keyring"
fi
short_id="${existing_fpr: -8}"
short_id_lower=$(echo "${short_id}" | tr '[:upper:]' '[:lower:]')
public_key_file="${short_id_lower}.gpg"
echo ""
echo "key fingerprint: ${existing_fpr}"
echo "short id: ${short_id}"
echo "public key file: ${public_key_file}"
# export the public key in ascii-armored format
gpg --homedir "${keyring_dir}" --batch --armor --export "${existing_fpr}" > "/tmp/${public_key_file}"
echo "exported public key to /tmp/${public_key_file}"
# sync public key to the remote rpm repo root (will not overwrite due to unique filename)
if rsync \
--archive \
--verbose \
--ignore-existing \
--rsync-path 'sudo rsync' \
--chown root:root \
--chmod F644 \
"/tmp/${public_key_file}" \
"${remote_host}:${remote_key_dir}/${public_key_file}"; then
echo "sync'd public key to ${remote_host}:${remote_key_dir}/${public_key_file}"
else
echo "failed to sync public key to ${remote_host}:${remote_key_dir}/${public_key_file}"
exit 1
fi
rm "/tmp/${public_key_file}"
echo ""
signing_subkey_fpr=$(gpg --homedir "${keyring_dir}" --batch --with-colons --list-keys "${key_uid}" \
| awk -F: '/^fpr:/ { fpr=$10 } /^sub:/ { getfpr=1; next } getfpr && /^fpr:/ { print $10; exit }')
echo "next steps:"
echo " 1. add the following secrets to the gitea repo:"
echo " RPM_SIGNING_KEY = output of: gpg --homedir ${keyring_dir} --armor --export-secret-subkeys ${signing_subkey_fpr}!"
echo " RPM_SIGNING_KEY_ID = ${key_uid}"
echo " 2. users can import the key with:"
echo " sudo rpm --import https://rpm.lair.cafe/${public_key_file}"
echo ""
echo " the master key (certify-only, no expiry) stays on this workstation in ${keyring_dir}."
echo " the signing subkey (1-year expiry) is what CI uses. rotate it with:"
echo " gpg --homedir ${keyring_dir} --quick-add-key ${existing_fpr} ed25519 sign 1y"