Sign official Breeze RMM agent releases with your own code-signing certificates — no fork, no Windows or Mac hardware, no per-download signing. One workflow run per Breeze release produces a complete signed release on this repository that your self-hosted Breeze instance consumes directly.
Full walkthrough (Azure Artifact Signing from zero, Apple Developer ID
enrollment, pointing your instance at your builds): Sign Your Own Agent
Packages in the Breeze docs (/deploy/sign-your-own-packages/).
- The workflow downloads the official release's signed
release-artifact-manifest.jsonand verifies it against the official Ed25519 key committed in this repo (official-release-key.pub) — before it touches any of your secrets. - It resolves the release tag and requires it to match the manifest's
sourceCommit(a moved tag aborts the run), then checks out the Breeze build scripts at that exact commit. - It downloads the official unsigned build outputs
(
*-unsigned.exe,breeze-*-darwin-*-unsigned), verifies each SHA-256 against the manifest, signs them with your certificates, builds the MSI / pkgs /Breeze Installer.app, and verifies every signature. - It mirrors the official assets this workflow does not re-sign (Linux
binaries, viewer/helper installers) after verifying them, generates
your release manifest, signs it with your Ed25519 manifest key,
and publishes release
v<version>on this repository. - Nothing in the manifest is guessed from a filename. Each asset's
platformTrustcomes either from the platform job's signing attestation — proof thatcodesign/Get-AuthenticodeSignatureactually inspected those bytes on a runner that had the tools — or, for mirrored assets, from the official manifest already verified in step 1.publishrefuses to build a manifest covering an asset that neither accounts for, so a component that slips past a signing step fails the run instead of being published as "signed".
Your agents never trust this repo's key directly — your Breeze API re-signs update manifests with its per-deployment key (standard since the BYO-signing release), so fleet trust is unchanged.
-
Click Use this template (a private copy is fine — the workflow only reads public official releases).
-
Run
./scripts/generate-manifest-key.shlocally and follow its output: store the private key as theRELEASE_MANIFEST_ED25519_PRIVATE_KEYsecret; keep the printed env block for step 6. -
Add the platform secrets for your signing mode (tables below).
-
Recommended: create a GitHub Environment named
signing(Settings → Environments), move the secrets there, and add yourself as a required reviewer — every signing run then needs an explicit approval. The workflow's signing jobs reference thesigningenvironment. Dry-run executions also run in thesigningenvironment, so with required reviewers even secret-free dry runs wait for your approval — this is expected and is a useful smoke test of the approval gate. -
Actions → Sign Breeze Release → Run workflow. Do a
dry-run: truepass first (no secrets needed) to validate the plumbing, then a real run. -
Point your instance at your builds (the run summary prints this block with your real key):
BINARY_SOURCE=github BINARY_GITHUB_REPOSITORY=<your-org>/<this-repo> BINARY_VERSION=<version> RELEASE_ARTIFACT_MANIFEST_PUBLIC_KEYS=<your raw base64 public key> AGENT_AUTO_PROMOTE=false # recommended for first adoption; promote explicitly
| Input | Values | Notes |
|---|---|---|
version |
X.Y.Z or X.Y.Z-suffix (no leading v) |
Must be an official Breeze release that publishes unsigned signing inputs. The run refuses to overwrite an existing v<version> release here. |
signing-mode |
azure-artifact-signing (default), pfx |
PFX is legacy / internal-PKI only — publicly trusted code-signing keys must live in HSMs (CA/B Forum, June 2023), so exportable PFX files are generally unavailable for new OV certs. |
platforms |
all (default), windows, macos |
Skip a platform only if your fleet has no such devices — a skipped platform's assets are absent from your release and those downloads will 404. A partial run also consumes the version: the release now exists, so a later run for the same version is refused and you would have to delete the release in the GitHub UI to add the other platform. |
dry-run |
false (default), true |
Download + verify + build with signing stubbed; no secrets or certs needed. Publishes nothing — assets land as the dry-run-unsigned-assets workflow artifact. Your manifest key is never used: the manifest is signed with a throwaway key generated in-run, and every asset is recorded platformTrust: none, so a dry-run bundle cannot be mistaken for a release. |
| Secret | Value |
|---|---|
RELEASE_MANIFEST_ED25519_PRIVATE_KEY |
PEM output of scripts/generate-manifest-key.sh. The public key is derived from it at run time — nothing else to store. |
Uses OIDC federated credentials (no client secret stored). The guide's Part 1 walks through creating each of these.
| Secret | Value |
|---|---|
AZURE_CLIENT_ID |
App registration (client) ID with a GitHub OIDC federated credential for this repo |
AZURE_TENANT_ID |
Entra tenant ID |
AZURE_SIGNING_ENDPOINT |
Artifact Signing account endpoint, e.g. https://eus.codesigning.azure.net |
AZURE_SIGNING_ACCOUNT_NAME |
Artifact Signing account name |
AZURE_CERT_PROFILE |
Certificate profile name (one profile — this repo does not split prod/prerelease) |
| Secret | Value |
|---|---|
WINDOWS_PFX_BASE64 |
base64 -w0 your-cert.pfx (macOS: base64 -i your-cert.pfx) |
WINDOWS_PFX_PASSWORD |
PFX password |
Optional repository variable PFX_TIMESTAMP_URL overrides the RFC 3161
timestamp server (default http://timestamp.digicert.com).
| Secret | Value |
|---|---|
APPLE_CERTIFICATE |
base64 of a .p12 export containing BOTH your Developer ID Application and Developer ID Installer certificates + keys |
APPLE_CERTIFICATE_PASSWORD |
.p12 export password |
APPLE_SIGNING_IDENTITY |
e.g. Developer ID Application: Your Org (TEAMID) |
APPLE_INSTALLER_IDENTITY |
e.g. Developer ID Installer: Your Org (TEAMID) |
APPLE_ID |
Apple ID email used for notarization |
APPLE_PASSWORD |
App-specific password for that Apple ID (not your account password; ASC API keys are not supported) |
APPLE_TEAM_ID |
10-character team ID |
The Windows MSI builds under the self-hosted edition identity —
ProductName "Breeze Agent (Self-Hosted)" and its own permanent
UpgradeCode, distinct from the ProductName "Breeze Agent" that hosted
Breeze distribution uses. This is intentional: the two identities can never
install on top of each other, and the self-hosted UpgradeCode is what your
fleet's upgrade lineage tracks — matching the public unsigned self-host MSI
Breeze publishes with each release, so signing it here doesn't fork your
fleet onto a different upgrade path. Signing a release from before this
edition parameter existed builds the original ("Breeze Agent") identity,
matching what that release actually shipped.
Signed by you: breeze-agent.msi, breeze-agent-windows-amd64.exe,
breeze-backup-windows-amd64.exe, breeze-watchdog-windows-amd64.exe,
breeze-user-helper-windows-amd64.exe,
breeze-{agent,backup,desktop-helper,watchdog}-darwin-{amd64,arm64},
breeze-agent-darwin-{amd64,arm64}.pkg, Breeze Installer.app.zip.
Mirrored from the official release (hash-verified against the official
manifest; not re-signed here — the viewer/helper installers keep LanternOps'
original Authenticode/Developer ID signatures, and their platformTrust is
carried over from the official manifest rather than re-derived):
breeze-{agent,backup,watchdog}-linux-{amd64,arm64},
breeze-viewer-{windows.msi,macos.dmg,linux.AppImage}, latest.json,
breeze-helper-{windows.msi,macos.dmg,linux.AppImage}.
Generated: release-artifact-manifest.json + .ed25519 (signed with your
manifest key), checksums.txt.
- SmartScreen reputation ramps over time. A correct signature does not mean an instant clean install experience — reputation accrues per certificate and per file hash. Signing once per release (what this repo does) is what lets it accrue at all.
- Publisher name: your organization appears as the publisher on
Breeze-branded binaries. That is expected; a full rebrand is the fork path
(
docs/signing/ARTIFACT_SIGNING_OPERATIONS.md, Model B). - Key rotation: when LanternOps rotates the official manifest key,
official-release-key.pubchanges here — pull template updates before signing a release made with the new key.