From b2b903bd472dd71473b87ce1d332464cc2f16286 Mon Sep 17 00:00:00 2001 From: benya Date: Thu, 23 Jul 2026 01:45:56 +0300 Subject: [PATCH] build: pin OpenWrt package signing keys --- .gitattributes | 1 + .github/workflows/build.yml | 2 -- CHECKLIST.md | 3 ++- deploy/luci-builder/Dockerfile | 21 +++++++++++---------- docs/package-repository.md | 12 +++++++++--- keys/openwrt/apk/rmm-openwrt.pem | 4 ++++ keys/openwrt/usign/7fb0908fb6bc82c8 | 2 ++ 7 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 keys/openwrt/apk/rmm-openwrt.pem create mode 100644 keys/openwrt/usign/7fb0908fb6bc82c8 diff --git a/.gitattributes b/.gitattributes index c8fa57c..c650d67 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,6 +6,7 @@ Dockerfile text eol=lf Caddyfile text eol=lf Makefile text eol=lf +keys/openwrt/** text eol=lf agent/openwrt/rmm-agent.init text eol=lf agent/package/rmm-agent/files/etc/init.d/rmm-agent text eol=lf agent/package/rmm-agent/files/usr/bin/rmm-agent text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2b91c1a..d8efb89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -150,7 +150,6 @@ jobs: uses: docker/build-push-action@v6 env: OPENWRT_USIGN_SECRET_B64: ${{ secrets.OPENWRT_USIGN_SECRET_B64 }} - OPENWRT_USIGN_PUBLIC_B64: ${{ secrets.OPENWRT_USIGN_PUBLIC_B64 }} OPENWRT_APK_SECRET_B64: ${{ secrets.OPENWRT_APK_SECRET_B64 }} with: context: . @@ -169,7 +168,6 @@ jobs: REPOSITORY_INDEX_REVISION=${{ github.run_id }} secret-envs: | openwrt_usign_secret_b64=OPENWRT_USIGN_SECRET_B64 - openwrt_usign_public_b64=OPENWRT_USIGN_PUBLIC_B64 openwrt_apk_secret_b64=OPENWRT_APK_SECRET_B64 cache-from: type=gha,scope=openwrt-${{ matrix.release }}-${{ matrix.label }} cache-to: type=gha,mode=max,scope=openwrt-${{ matrix.release }}-${{ matrix.label }} diff --git a/CHECKLIST.md b/CHECKLIST.md index 583ee97..137c745 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md @@ -22,7 +22,8 @@ ## Обязательное перед следующим production-релизом -- [ ] Сгенерировать и офлайн сохранить ключи `usign`/APK, добавить base64-значения в GitHub Actions Secrets. +- [x] Сгенерировать ключи `usign`/APK и зафиксировать проверяемые публичные ключи. +- [ ] Сохранить приватные ключи в зашифрованной офлайн-копии и добавить два base64-значения в GitHub Actions Secrets. - [ ] Включить GitHub Pages из Actions и проверить первый подписанный package feed на реальном роутере. - [ ] Выпустить первый `server-v*`, проверить Cosign/provenance и закрепить `RMM_RELEASE_VERSION` в production `.env`. - [ ] Настроить SMTP и/или `RMM_TELEGRAM_BOT_TOKEN` в production environment. diff --git a/deploy/luci-builder/Dockerfile b/deploy/luci-builder/Dockerfile index ffca304..85d8b84 100644 --- a/deploy/luci-builder/Dockerfile +++ b/deploy/luci-builder/Dockerfile @@ -147,8 +147,9 @@ RUN printf '%s\n' 'CONFIG_PACKAGE_luci-app-rmm-agent=m' >> .config \ RUN make -j1 package/luci-app-rmm-agent/compile V=s +COPY --chown=builder:builder keys/openwrt /home/builder/release-keys + RUN --mount=type=secret,id=openwrt_usign_secret_b64,uid=1000,required=false \ - --mount=type=secret,id=openwrt_usign_public_b64,uid=1000,required=false \ --mount=type=secret,id=openwrt_apk_secret_b64,uid=1000,required=false \ test -n "${REPOSITORY_INDEX_REVISION}" \ && mkdir -p /home/builder/artifacts \ @@ -163,16 +164,14 @@ RUN --mount=type=secret,id=openwrt_usign_secret_b64,uid=1000,required=false \ && if find . -maxdepth 1 -type f -name '*.ipk' -print -quit | grep -q .; then \ /home/builder/sdk/scripts/ipkg-make-index.sh . > Packages; \ gzip -9nc Packages > Packages.gz; \ - if [ -s /run/secrets/openwrt_usign_secret_b64 ] \ - && [ -s /run/secrets/openwrt_usign_public_b64 ]; then \ + if [ -s /run/secrets/openwrt_usign_secret_b64 ]; then \ base64 -d /run/secrets/openwrt_usign_secret_b64 > /tmp/usign.sec; \ - base64 -d /run/secrets/openwrt_usign_public_b64 > /tmp/usign.pub; \ chmod 600 /tmp/usign.sec; \ /home/builder/sdk/staging_dir/host/bin/usign -S -m Packages -s /tmp/usign.sec; \ - /home/builder/sdk/staging_dir/host/bin/usign -V -m Packages -p /tmp/usign.pub; \ - key_id="$(/home/builder/sdk/staging_dir/host/bin/usign -F -p /tmp/usign.pub)"; \ - cp /tmp/usign.pub "${key_id}"; \ - rm -f /tmp/usign.sec /tmp/usign.pub; \ + /home/builder/sdk/staging_dir/host/bin/usign -V -m Packages \ + -p /home/builder/release-keys/usign/7fb0908fb6bc82c8; \ + cp /home/builder/release-keys/usign/7fb0908fb6bc82c8 ./; \ + rm -f /tmp/usign.sec; \ elif [ "${REQUIRE_NATIVE_SIGNATURE}" = "true" ]; then \ echo 'IPK release signing keys are required' >&2; \ exit 1; \ @@ -182,7 +181,9 @@ RUN --mount=type=secret,id=openwrt_usign_secret_b64,uid=1000,required=false \ base64 -d /run/secrets/openwrt_apk_secret_b64 > /tmp/apk-signing.pem; \ chmod 600 /tmp/apk-signing.pem; \ /home/builder/sdk/staging_dir/host/bin/openssl ec \ - -in /tmp/apk-signing.pem -pubout -out rmm-openwrt.pem; \ + -in /tmp/apk-signing.pem -pubout -out /tmp/apk-signing.pub.pem; \ + cmp /tmp/apk-signing.pub.pem /home/builder/release-keys/apk/rmm-openwrt.pem; \ + cp /home/builder/release-keys/apk/rmm-openwrt.pem ./; \ /home/builder/sdk/staging_dir/host/bin/apk mkndx \ --root /home/builder/sdk \ --keys-dir /home/builder/artifacts \ @@ -190,7 +191,7 @@ RUN --mount=type=secret,id=openwrt_usign_secret_b64,uid=1000,required=false \ --sign /tmp/apk-signing.pem \ --output packages.adb \ ./*.apk; \ - rm -f /tmp/apk-signing.pem; \ + rm -f /tmp/apk-signing.pem /tmp/apk-signing.pub.pem; \ elif [ "${REQUIRE_NATIVE_SIGNATURE}" = "true" ]; then \ echo 'APK release signing key is required' >&2; \ exit 1; \ diff --git a/docs/package-repository.md b/docs/package-repository.md index ae25b2a..07125da 100644 --- a/docs/package-repository.md +++ b/docs/package-repository.md @@ -37,7 +37,6 @@ Encode the keys without printing private material into CI logs: ```sh base64 -w0 release-keys/openwrt-usign.sec > release-keys/openwrt-usign.sec.b64 -base64 -w0 release-keys/openwrt-usign.pub > release-keys/openwrt-usign.pub.b64 base64 -w0 release-keys/openwrt-apk.pem > release-keys/openwrt-apk.pem.b64 ``` @@ -46,9 +45,16 @@ Create these GitHub Actions repository secrets from the corresponding `.b64` fil | Secret | Source file | | --- | --- | | `OPENWRT_USIGN_SECRET_B64` | `openwrt-usign.sec.b64` | -| `OPENWRT_USIGN_PUBLIC_B64` | `openwrt-usign.pub.b64` | | `OPENWRT_APK_SECRET_B64` | `openwrt-apk.pem.b64` | +The public keys are committed under `keys/openwrt/`. Their expected identifiers are: + +- usign key ID: `7fb0908fb6bc82c8`; +- APK public key SHA256: `ce6f190c937961db306ddc3cbe138a877157d97252a2c8290980c43fc4f55f26`. + +The release build verifies that each private key matches the committed public key before +publishing a signed feed. + An `agent-v*` release fails closed when the key required by an OpenWrt generation is missing. Manual workflow runs may still create unsigned test artifacts. BuildKit secret mounts expose private keys only to the repository-index build step; private keys are not @@ -62,7 +68,7 @@ OpenWrt 24.10: ```sh feed='https://benya9669.github.io/openwrt-rmm/feeds/stable/openwrt/24.10.7/ramips-mt7621' key_base='https://benya9669.github.io/openwrt-rmm/keys/usign' -key_id='<16-character-key-id>' +key_id='7fb0908fb6bc82c8' wget -O "/etc/opkg/keys/${key_id}" "${key_base}/${key_id}" printf 'src/gz rmm %s\n' "$feed" > /etc/opkg/customfeeds.conf.d/rmm.conf diff --git a/keys/openwrt/apk/rmm-openwrt.pem b/keys/openwrt/apk/rmm-openwrt.pem new file mode 100644 index 0000000..d02a0ec --- /dev/null +++ b/keys/openwrt/apk/rmm-openwrt.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzzOGQYCwp/8xm200pVjwhWKNLYXU +2+ywR0sD/x/ApS6ga2g2597ASu85iM0O1s3W8Va70EiaFoMG1T4EWllH3Q== +-----END PUBLIC KEY----- diff --git a/keys/openwrt/usign/7fb0908fb6bc82c8 b/keys/openwrt/usign/7fb0908fb6bc82c8 new file mode 100644 index 0000000..eb2c530 --- /dev/null +++ b/keys/openwrt/usign/7fb0908fb6bc82c8 @@ -0,0 +1,2 @@ +untrusted comment: OpenWrt RMM package repository +RWR/sJCPtryCyApmLYI5HhFbkl1DvdafP1AhonsiwbJwyDECWMC1Z6jK