Skip to content

Commit dc913ec

Browse files
authored
Fix GPG keyring location for systemd-sysupdate (#155)
* fix: move GPG key to systemd-sysupdate expected location systemd-sysupdate only checks global keyrings for signature verification: - /usr/lib/systemd/import-pubring.gpg (system) - /etc/systemd/import-pubring.gpg (admin) The previous location (/etc/sysupdate.alloy.d/alloy.gpg) was not used by systemd-sysupdate. This change moves the key to the correct location so SHA256SUMS.gpg signature verification works. Implements: GHO-59 * feat: implement dynamic GPG keyring merge for systemd-sysupdate Instead of statically placing the GPG key at /etc/systemd/import-pubring.gpg (which would override the system keyring), implement a dynamic merge approach: - Store Alloy signing key at /etc/systemd/alloy-sysext.gpg.pub - Add merge script at /usr/local/bin/sysupdate-merge-keyring.sh that: - Checks for .pgp (newer systemd) before .gpg (legacy) - Copies system keyring from /usr/lib/systemd/ to /etc/systemd/ - Imports Alloy key using gpg to merge keyrings - Cleans up temporary GPG home directory - Add sysupdate-import-pubring.service that runs before systemd-sysupdate This ensures the Alloy signing key is always appended to whatever keys come with the base image (e.g., Fedora/Ubuntu legacy keys), even if the base image is updated with different keys.
1 parent 7bf7c43 commit dc913ec

2 files changed

Lines changed: 89 additions & 4 deletions

File tree

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ All Alloy sysext images are cryptographically signed. The instance verifies sign
379379
before installing updates via systemd-sysupdate.
380380

381381
- **Signing Key:** `Alloy Sysext Signing Key <alloy-sysext@separationofconcerns.dev>`
382-
- **Public Key Location:** `/etc/sysupdate.alloy.d/alloy.gpg`
382+
- **Public Key Location:** `/etc/systemd/import-pubring.gpg`
383383
- **Sysupdate Config:** `/etc/sysupdate.alloy.d/alloy.conf` with `Verify=true`
384384
- **Signature Files:** `.asc` files stored alongside images in R2
385385

@@ -438,7 +438,7 @@ cat /etc/sysupdate.alloy.d/alloy.conf
438438
systemd-sysupdate -C alloy list
439439

440440
# Check the public key
441-
cat /etc/sysupdate.alloy.d/alloy.gpg
441+
cat /etc/systemd/import-pubring.gpg
442442
```
443443

444444
**Note:** Changing the Butane configuration (including the Alloy version) will cause

opentofu/modules/vultr/instance/userdata/ghost.bu

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ storage:
6060
Path=/opt/extensions/alloy/
6161
CurrentSymlink=/etc/extensions/alloy.raw
6262

63-
# GPG public key for verifying Alloy sysext signatures
63+
# GPG public key for verifying Alloy sysext signatures (SHA256SUMS.gpg)
64+
# This key is merged into /etc/systemd/import-pubring.gpg by the
65+
# sysupdate-import-pubring.service at boot time. The merge preserves
66+
# any existing keys from the base image (e.g., Fedora/Ubuntu legacy keys).
6467
# Key: Alloy Sysext Signing Key <alloy-sysext@separationofconcerns.dev>
65-
- path: /etc/sysupdate.alloy.d/alloy.gpg
68+
- path: /etc/systemd/alloy-sysext.gpg.pub
6669
mode: 0644
6770
contents:
6871
inline: |
@@ -96,6 +99,69 @@ storage:
9699
=8FOV
97100
-----END PGP PUBLIC KEY BLOCK-----
98101

102+
# Script to merge system GPG keyring with Alloy signing key
103+
# Checks for .pgp (newer systemd) first, then falls back to .gpg (legacy)
104+
- path: /usr/local/bin/sysupdate-merge-keyring.sh
105+
mode: 0755
106+
contents:
107+
inline: |
108+
#!/bin/bash
109+
# Merge system import-pubring with Alloy sysext signing key
110+
# systemd-sysupdate checks /etc/systemd/ first, then /usr/lib/systemd/
111+
# We copy the system keyring to /etc and append our key to preserve both
112+
set -euo pipefail
113+
114+
SYS_KEYRING=""
115+
ETC_KEYRING="/etc/systemd/import-pubring.gpg"
116+
ALLOY_KEY="/etc/systemd/alloy-sysext.gpg.pub"
117+
118+
# Check for system keyring (.pgp preferred, .gpg fallback)
119+
if [[ -f /usr/lib/systemd/import-pubring.pgp ]]; then
120+
SYS_KEYRING="/usr/lib/systemd/import-pubring.pgp"
121+
ETC_KEYRING="/etc/systemd/import-pubring.pgp"
122+
elif [[ -f /usr/lib/systemd/import-pubring.gpg ]]; then
123+
SYS_KEYRING="/usr/lib/systemd/import-pubring.gpg"
124+
ETC_KEYRING="/etc/systemd/import-pubring.gpg"
125+
fi
126+
127+
# Create /etc/systemd directory if needed
128+
mkdir -p /etc/systemd
129+
130+
if [[ -n "$SYS_KEYRING" ]]; then
131+
echo "Copying system keyring from $SYS_KEYRING to $ETC_KEYRING"
132+
cp "$SYS_KEYRING" "$ETC_KEYRING"
133+
else
134+
echo "No system keyring found, creating new keyring at $ETC_KEYRING"
135+
touch "$ETC_KEYRING"
136+
fi
137+
138+
# Import Alloy signing key into the keyring
139+
if [[ -f "$ALLOY_KEY" ]]; then
140+
echo "Importing Alloy signing key into $ETC_KEYRING"
141+
# Use gpg to import key into keyring file
142+
GNUPGHOME=$(mktemp -d)
143+
export GNUPGHOME
144+
trap 'rm -rf "$GNUPGHOME"' EXIT
145+
146+
# Import existing keyring if it has content
147+
if [[ -s "$ETC_KEYRING" ]]; then
148+
gpg --batch --quiet --import "$ETC_KEYRING" 2>/dev/null || true
149+
fi
150+
151+
# Import Alloy key
152+
gpg --batch --quiet --import "$ALLOY_KEY"
153+
154+
# Export merged keyring
155+
gpg --batch --quiet --export > "$ETC_KEYRING"
156+
157+
echo "Keyring merge complete"
158+
else
159+
echo "Warning: Alloy signing key not found at $ALLOY_KEY"
160+
fi
161+
162+
chmod 0644 "$ETC_KEYRING"
163+
echo "Keyring ready at $ETC_KEYRING"
164+
99165
- path: /etc/systemd/system/ghost-compose.service
100166
mode: 0644
101167
contents:
@@ -400,6 +466,25 @@ systemd:
400466
- name: locksmithd.service
401467
enabled: true
402468

469+
# Merge system GPG keyring with Alloy signing key before sysupdate runs
470+
# This ensures systemd-sysupdate can verify both system packages and Alloy sysext
471+
# The merge preserves existing keys from the base image while adding our key
472+
- name: sysupdate-import-pubring.service
473+
enabled: true
474+
contents: |
475+
[Unit]
476+
Description=Merge GPG keyring for systemd-sysupdate
477+
Before=systemd-sysupdate.service
478+
ConditionPathExists=/etc/systemd/alloy-sysext.gpg.pub
479+
480+
[Service]
481+
Type=oneshot
482+
ExecStart=/usr/local/bin/sysupdate-merge-keyring.sh
483+
RemainAfterExit=yes
484+
485+
[Install]
486+
WantedBy=multi-user.target
487+
403488
- name: systemd-sysupdate.timer
404489
enabled: true
405490

0 commit comments

Comments
 (0)