Skip to content

Commit 6b00c86

Browse files
Przemek Zglinickiclaude
andcommitted
ci: sign RPM packages before pushing to GCP Artifact Registry
- Add sign_rpm() to push_pkg_to_gcp_ar.sh: fetches the Redpanda GPG private key from AWS Secrets Manager (sdlc/prod/github/rpm_signing_key_private), signs each RPM with rpmsign --resign, verifies the signature using a temp RPM database, then uploads to GCP AR - Fix signature verification to use rpm --dbpath <tmpdb> so the GPG check actually validates the signature (plain rpm --checksig ignores GNUPGHOME and checks the system keyring, returning exit 0 even for NOKEY) - Add test-push-to-gcp-ar CI job: generates a throwaway GPG key, builds a minimal RPM, mocks aws and gcloud, and asserts signing + routing for GA (redpanda-yum), RC (redpanda-unstable-yum), DEB (redpanda-apt), and missing-region error cases Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9ae58ec commit 6b00c86

3 files changed

Lines changed: 128 additions & 1 deletion

File tree

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ jobs:
7474
tar -C "$RUNNER_TEMP/microsoft" -xf "$RUNNER_TEMP/msgo.tgz"
7575
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
7676
77+
- name: Install rpm (provides rpmsign for RPM package signing)
78+
run: sudo apt-get install -y rpm gnupg2
79+
7780
- name: Release Notes
7881
run: ./resources/scripts/release_notes.sh > ./release_notes.md
7982

.github/workflows/test.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,91 @@ jobs:
6262
skip-cache: true
6363
skip-save-cache: true
6464

65+
test-push-to-gcp-ar:
66+
runs-on: ubuntu-latest
67+
steps:
68+
69+
- name: Checkout code
70+
uses: actions/checkout@v6
71+
72+
- name: Install rpm tools
73+
run: sudo apt-get install -y rpm gnupg2
74+
75+
- name: Set up test GPG key and test RPM
76+
run: |
77+
# Generate a throwaway GPG key — no passphrase, expires never
78+
printf '%s\n' \
79+
'%no-protection' \
80+
'Key-Type: RSA' \
81+
'Key-Length: 2048' \
82+
'Name-Real: Test Signing Key' \
83+
'Name-Email: test@redpanda.com' \
84+
'Expire-Date: 0' \
85+
| gpg --batch --gen-key
86+
# Export private key so the aws mock can serve it
87+
gpg --armor --export-secret-keys > /tmp/test-signing-key.asc
88+
89+
# Build a minimal empty RPM
90+
mkdir -p /tmp/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
91+
printf '%s\n' \
92+
'Name: test-pkg' \
93+
'Version: 1.0.0' \
94+
'Release: 1' \
95+
'Summary: Test package for RPM signing CI' \
96+
'License: MIT' \
97+
'BuildArch: noarch' \
98+
'%description' \
99+
'Minimal test RPM.' \
100+
'%install' \
101+
'mkdir -p %{buildroot}' \
102+
'%files' \
103+
> /tmp/rpmbuild/SPECS/test-pkg.spec
104+
rpmbuild --define "_topdir /tmp/rpmbuild" -bb /tmp/rpmbuild/SPECS/test-pkg.spec
105+
cp /tmp/rpmbuild/RPMS/noarch/test-pkg-1.0.0-1.noarch.rpm /tmp/test.rpm
106+
107+
- name: Mock aws and gcloud CLIs
108+
run: |
109+
# aws: return the test private key for any secretsmanager get-secret-value call
110+
printf '#!/bin/bash\ncat /tmp/test-signing-key.asc\n' \
111+
| sudo tee /usr/local/bin/aws > /dev/null
112+
sudo chmod +x /usr/local/bin/aws
113+
# gcloud: echo arguments so we can assert routing
114+
printf '#!/bin/bash\necho "gcloud $*"\n' \
115+
| sudo tee /usr/local/bin/gcloud > /dev/null
116+
sudo chmod +x /usr/local/bin/gcloud
117+
118+
- name: Test RPM GA — signed and routed to redpanda-yum
119+
env:
120+
AWS_DEFAULT_REGION: us-east-1
121+
run: |
122+
out=$(./resources/scripts/push_pkg_to_gcp_ar.sh /tmp/test.rpm 1.0.0)
123+
echo "$out"
124+
echo "$out" | grep -q "artifacts yum upload redpanda-yum"
125+
126+
- name: Test RPM RC — routed to redpanda-unstable-yum
127+
env:
128+
AWS_DEFAULT_REGION: us-east-1
129+
run: |
130+
out=$(./resources/scripts/push_pkg_to_gcp_ar.sh /tmp/test.rpm 1.0.0-rc1)
131+
echo "$out"
132+
echo "$out" | grep -q "artifacts yum upload redpanda-unstable-yum"
133+
134+
- name: Test DEB — skips signing, routed to redpanda-apt
135+
run: |
136+
touch /tmp/test.deb
137+
out=$(./resources/scripts/push_pkg_to_gcp_ar.sh /tmp/test.deb 1.0.0)
138+
echo "$out"
139+
echo "$out" | grep -q "artifacts apt upload redpanda-apt"
140+
141+
- name: Test missing AWS region — exits with error
142+
env:
143+
AWS_DEFAULT_REGION: ""
144+
AWS_REGION: ""
145+
run: |
146+
out=$(./resources/scripts/push_pkg_to_gcp_ar.sh /tmp/test.rpm 1.0.0 2>&1) && {
147+
echo "ERROR: expected non-zero exit but got 0" >&2; exit 1
148+
} || echo "$out" | grep -q "AWS_DEFAULT_REGION"
149+
65150
test-push-to-cloudsmith:
66151
runs-on: ubuntu-latest
67152
env:

resources/scripts/push_pkg_to_gcp_ar.sh

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Push a rpm or deb to GCP Artifact Registry
44

5-
set -ex
5+
set -euo pipefail
66

77
PKG_FILE=$1
88
PKG_VERSION=$2
@@ -42,8 +42,47 @@ else
4242
repo="redpanda-unstable"
4343
fi
4444

45+
sign_rpm() {
46+
local pkg=$1
47+
48+
# Pre-flight: AWS_DEFAULT_REGION (or AWS_REGION) must be set; the aws CLI
49+
# reads it from the environment, but we check early for a clear error message.
50+
local region=${AWS_DEFAULT_REGION:-${AWS_REGION:-}}
51+
if [[ -z "$region" ]]; then
52+
echo "ERROR: AWS_DEFAULT_REGION or AWS_REGION must be set for RPM signing"
53+
exit 1
54+
fi
55+
56+
local gnupghome tmpdb pubkey
57+
gnupghome=$(mktemp -d)
58+
tmpdb=$(mktemp -d)
59+
pubkey=$(mktemp)
60+
trap 'rm -rf "$gnupghome" "$tmpdb" "$pubkey"' RETURN EXIT
61+
62+
aws secretsmanager get-secret-value \
63+
--secret-id sdlc/prod/github/rpm_signing_key_private \
64+
--query SecretString \
65+
--output text | GNUPGHOME="$gnupghome" gpg --batch --import
66+
67+
local key_id
68+
key_id=$(GNUPGHOME="$gnupghome" gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5}' | head -1)
69+
if [[ -z "$key_id" ]]; then
70+
echo "ERROR: no secret key found after import — check the secret contents"
71+
exit 1
72+
fi
73+
74+
GNUPGHOME="$gnupghome" rpmsign --define "_gpg_name $key_id" --resign "$pkg"
75+
76+
# Verify against our key using a temp RPM database — rpm --checksig checks
77+
# the RPM keyring (not GNUPGHOME), so we must import the key into a temp db.
78+
GNUPGHOME="$gnupghome" gpg --armor --export "$key_id" >"$pubkey"
79+
rpm --dbpath "$tmpdb" --import "$pubkey"
80+
rpm --dbpath "$tmpdb" --checksig "$pkg"
81+
}
82+
4583
if [[ "$PKG_TYPE" == "deb" ]]; then
4684
gcloud artifacts apt upload "${repo}-apt" --location=us-central1 --source="$PKG_FILE" --project=production-devprod
4785
else
86+
sign_rpm "$PKG_FILE"
4887
gcloud artifacts yum upload "${repo}-yum" --location=us-central1 --source="$PKG_FILE" --project=production-devprod
4988
fi

0 commit comments

Comments
 (0)