Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/actions/sign-update/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Sign update package
description: Create a detached ECDSA signature with OpenSSL

inputs:
artifact:
description: Package file to sign
required: true
private-key-pem:
description: PEM-encoded ECDSA private key
required: true
public-key-sha256:
description: Expected SHA-256 fingerprint of the PKIX DER public key
required: true

runs:
using: composite
steps:
- shell: bash
env:
ARTIFACT: ${{ inputs.artifact }}
EXPECTED_PUBLIC_KEY_SHA256: ${{ inputs.public-key-sha256 }}
UPDATE_SIGNING_KEY_PEM: ${{ inputs.private-key-pem }}
run: |
set -euo pipefail
umask 077
key="${RUNNER_TEMP}/snclient-update-signing-key.pem"
public_key="${RUNNER_TEMP}/snclient-update-public-key.der"
trap 'rm -f "${key}" "${public_key}"' EXIT
printf '%s\n' "${UPDATE_SIGNING_KEY_PEM}" > "${key}"
openssl pkey -in "${key}" -pubout -outform DER -out "${public_key}"
actual_fingerprint="$(sha256sum "${public_key}" | cut -d' ' -f1)"
if [[ "${actual_fingerprint}" != "${EXPECTED_PUBLIC_KEY_SHA256}" ]]; then
echo "::error::Update signing key does not match the built-in public key"
exit 1
fi
openssl dgst -sha256 -sign "${key}" -out "${ARTIFACT}.sig" "${ARTIFACT}"
80 changes: 77 additions & 3 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ on:
permissions:
contents: read

env:
UPDATE_PUBLIC_KEY_SHA256: "f74bfbce4461efa8d357d4a639ba8b1f74668385dcd3a85cd238accc05fdb2c0"

jobs:
get-version:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -605,6 +608,59 @@ jobs:
name: "${{ env.BIN }}"


sign-dev-update-assets:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
include:
- asset_os: windows
go-arch: i386
extension: msi
- asset_os: windows
go-arch: x86_64
extension: msi
- asset_os: windows
go-arch: aarch64
extension: msi
- asset_os: linux
go-arch: i386
extension: rpm
- asset_os: linux
go-arch: x86_64
extension: rpm
- asset_os: linux
go-arch: aarch64
extension: rpm
- asset_os: osx
go-arch: x86_64
extension: pkg
- asset_os: osx
go-arch: aarch64
extension: pkg
needs: [get-version, pkg-msi, pkg-rpm, pkg-osx]
runs-on: ubuntu-latest
environment: update-dev
env:
ASSET: "snclient-${{needs.get-version.outputs.version}}-${{ matrix.asset_os }}-${{ matrix.go-arch }}.${{ matrix.extension }}"
steps:
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
name: "${{ env.ASSET }}"
- uses: ./.github/actions/sign-update
with:
artifact: ${{ env.ASSET }}
private-key-pem: ${{ secrets.SNCLIENT_UPDATE_PRIVATE_KEY_PEM }}
public-key-sha256: ${{ env.UPDATE_PUBLIC_KEY_SHA256 }}
- uses: actions/upload-artifact@v7.0.1
with:
name: "${{ env.ASSET }}.sig"
path: "${{ env.ASSET }}.sig"
if-no-files-found: error
archive: false


# remove those artifacts which have been converted to .deb or .rpm files
clean-tmp-files:
strategy:
Expand Down Expand Up @@ -784,6 +840,7 @@ jobs:
go-arch: [i386, x86_64, aarch64]
runs-on: ubuntu-latest
needs: [get-version,make-release]
environment: update-stable
permissions:
contents: write
env:
Expand All @@ -794,7 +851,12 @@ jobs:
- uses: actions/download-artifact@v8
with:
name: "${{ env.BIN }}.msi"
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.msi
- uses: ./.github/actions/sign-update
with:
artifact: ${{ env.BIN }}.msi
private-key-pem: ${{ secrets.SNCLIENT_UPDATE_PRIVATE_KEY_PEM }}
public-key-sha256: ${{ env.UPDATE_PUBLIC_KEY_SHA256 }}
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.msi ${{ env.BIN }}.msi.sig


upload-linux-deb-assets:
Expand Down Expand Up @@ -828,6 +890,7 @@ jobs:
go-arch: [i386, x86_64, aarch64]
runs-on: ubuntu-latest
needs: [get-version,make-release]
environment: update-stable
permissions:
contents: write
env:
Expand All @@ -838,7 +901,12 @@ jobs:
- uses: actions/download-artifact@v8
with:
name: "${{ env.BIN }}.rpm"
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.rpm
- uses: ./.github/actions/sign-update
with:
artifact: ${{ env.BIN }}.rpm
private-key-pem: ${{ secrets.SNCLIENT_UPDATE_PRIVATE_KEY_PEM }}
public-key-sha256: ${{ env.UPDATE_PUBLIC_KEY_SHA256 }}
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.rpm ${{ env.BIN }}.rpm.sig


upload-linux-apk-assets:
Expand Down Expand Up @@ -872,6 +940,7 @@ jobs:
go-arch: [x86_64, aarch64]
runs-on: ubuntu-latest
needs: [get-version,make-release]
environment: update-stable
permissions:
contents: write
env:
Expand All @@ -882,7 +951,12 @@ jobs:
- uses: actions/download-artifact@v8
with:
name: "${{ env.BIN }}.pkg"
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.pkg
- uses: ./.github/actions/sign-update
with:
artifact: ${{ env.BIN }}.pkg
private-key-pem: ${{ secrets.SNCLIENT_UPDATE_PRIVATE_KEY_PEM }}
public-key-sha256: ${{ env.UPDATE_PUBLIC_KEY_SHA256 }}
- run: gh release upload v${{needs.get-version.outputs.version}} ${{ env.BIN }}.pkg ${{ env.BIN }}.pkg.sig


upload-binary-release-assets:
Expand Down
39 changes: 39 additions & 0 deletions docs/updates/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Create or edit `/etc/snclient/snclient_local.ini` (on windows: `C:\Program Files
[/settings/updates]
automatic updates = enabled
automatic restart = enabled
verify signature = true
```

This will update SNClient to the latest stable release.
Expand All @@ -39,6 +40,7 @@ add the dev channel as well.
[/settings/updates]
automatic updates = enabled
automatic restart = enabled
verify signature = true
channel = stable,dev

[/settings/updates/channel/dev]
Expand All @@ -50,6 +52,43 @@ In order to use the dev channel, you need to create a github token here: [github

Unfortunately it is not possible to download the build artifacts without a token.

Update signatures are verified by default with the public key built into
SNClient. Missing or invalid signatures abort the update. For manual recovery
from an unsigned source, verification can be explicitly disabled with
`verify signature = false` in `/settings/updates`.

The release workflow expects the same PEM-encoded ECDSA P-256 private key in both
GitHub environments:

- `SNCLIENT_UPDATE_PRIVATE_KEY_PEM` in the `update-stable` environment
- `SNCLIENT_UPDATE_PRIVATE_KEY_PEM` in the `update-dev` environment

The stable workflow signs the final RPM, MSI and PKG release assets. Development
signatures are created only for package artifacts built from a push to the
`main` branch. OpenSSL generates each binary `.sig` sidecar as an ASN.1/DER ECDSA
signature over the SHA-256 digest of the exact package bytes.

Generate the signing key once outside the repository:

```sh
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out update-private.pem
openssl pkey -in update-private.pem -pubout -out update-public.pem
```

Store the full private PEM as the secret in both environments. The client
stores the public key as base64-encoded PKIX DER in `update_signature.go`:

```sh
openssl pkey -in update-private.pem -pubout -outform DER | base64 -w0
```

The workflow also pins the SHA-256 fingerprint of the same DER public key and
fails before signing if the configured secret does not match:

```sh
openssl pkey -in update-private.pem -pubout -outform DER | sha256sum
```

### Debian / Ubuntu

On Debian and Ubuntu you can make use of the `unattended-upgrades` package.
Expand Down
3 changes: 2 additions & 1 deletion pkg/snclient/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ var DefaultConfig = map[string]ConfigData{
"nasty characters": DefaultNastyCharacters,
},
"/settings/updates": {
"channel": "stable",
"channel": "stable",
"verify signature": "true",
},
"/settings/updates/channel": {
"stable": "https://api.github.com/repos/ConSol-monitoring/snclient/releases",
Expand Down
3 changes: 3 additions & 0 deletions pkg/snclient/t/configs/snclient_incl.ini
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ automatic restart = disabled
; channel - comma separated list of channel to search for updates.
channel = stable

; verify signature - Verify downloaded updates with the built-in channel key.
verify signature = true

; pre release - Control if pre releases from the stable channel should be considered as well.
pre release = false

Expand Down
Loading