Skip to content

Add opt-in Windows Authenticode signing via Azure Trusted Signing (CE-424)#100

Open
c1-squire-dev[bot] wants to merge 1 commit into
mainfrom
john/CE-424/windows-authenticode-signing
Open

Add opt-in Windows Authenticode signing via Azure Trusted Signing (CE-424)#100
c1-squire-dev[bot] wants to merge 1 commit into
mainfrom
john/CE-424/windows-authenticode-signing

Conversation

@c1-squire-dev

@c1-squire-dev c1-squire-dev Bot commented Jun 23, 2026

Copy link
Copy Markdown

Summary

Windows .exe and .msi connector artifacts are currently only Sigstore (cosign) signed. Sigstore proves supply-chain provenance but is not recognized by Windows SmartScreen, so downloaded connector executables (e.g. baton-active-directory) trigger a SmartScreen warning — CE-424.

This PR adds Authenticode signing to the shared goreleaser-windows release job using Azure Trusted Signing, the approach already scoped in the repo's own docs as "Stage 2" and tracked in CE-178.

Can it be supported? Yes.

The goreleaser-windows job already runs on a native windows-latest runner with id-token: write (OIDC) and produces the unsigned .exe/.msi. Azure Trusted Signing plugs in cleanly with no long-lived certificate material in secrets (auth is via GitHub OIDC), and gives immediate SmartScreen reputation (unlike OV certs, which must accrue download reputation).

Design

The feature is opt-in via a new windows_authenticode_signing input (default false), so every connector keeps releasing unchanged until the Azure Trusted Signing account is provisioned (CE-178 is blocked on IT provisioning).

When enabled, the goreleaser-windows job:

  1. Logs in to Azure via azure/login (OIDC).
  2. Installs the Microsoft sign CLI.
  3. Signs the raw .exe in a GoReleaser build post-hookbefore it is packaged — so the binary inside both the .zip and the .msi carries the signature. This matters because the .exe extracted from the zip inherits Mark-of-the-Web and is what triggered the SmartScreen warning in the ticket.
  4. Signs the .msi in place via a GoReleaser signs entry ordered ahead of the existing cosign signature, so the Sigstore .sig/.cert and all downstream hashes/attestations/manifests cover the Authenticode-signed bytes.

All signing is delegated to scripts/sign-windows-authenticode.ps1, which runs sign code trusted-signing and then verifies with Get-AuthenticodeSignature.

The signing config is injected into the generated GoReleaser config using the same envsubst block pattern the repo already uses for Docker extra_files, so the template stays valid YAML when signing is off (verified both ways).

Changes

  • .github/workflows/release.yaml — new inputs (windows_authenticode_signing, trusted_signing_endpoint, trusted_signing_account_name, trusted_signing_certificate_profile), new optional secrets (AZURE_CLIENT_ID/AZURE_TENANT_ID/AZURE_SUBSCRIPTION_ID), up-front validation, Azure login + sign install steps, and conditional signing-config injection.
  • templates/.goreleaser-windows-template.yaml.tmpl — two injection points for the build hook and MSI signs entry.
  • scripts/sign-windows-authenticode.ps1 — new signing wrapper.
  • cmd/generate-windows-manifest/main.go — updated stale Stage-2 comment.
  • README.md, docs/release-workflow.md — caller usage, Azure setup, verification.

Required to roll out (post-merge, once Azure is provisioned)

  1. Provision an Azure Trusted Signing account + certificate profile.
  2. Create an Azure AD app with a federated credential trusting the connector repos' GitHub OIDC subjects; grant it the Trusted Signing Certificate Profile Signer role.
  3. Add the AZURE_* secrets, set windows_authenticode_signing: true and the trusted_signing_* inputs in the connector's release workflow.

Testing

  • release.yaml validated as YAML; Windows GoReleaser template rendered in both enabled/disabled modes and parsed — disabled adds no hooks, enabled orders authenticode-msi before cosign-msi.
  • go build ./cmd/generate-windows-manifest passes.
  • ⚠️ End-to-end signing cannot be exercised until the Azure Trusted Signing account exists (CE-178). The first real run should be validated on a test connector (baton-github-test / baton-runner) per docs/release-workflow.md, including pinning the sign tool version and confirming Get-AuthenticodeSignature reports Valid.

🤖 Generated with Claude Code


🏰 Squire environment: wise-narwhal-72864
Task: 092dff13-086e-4539-b9a2-628381b0e134

Windows .exe and .msi artifacts are currently only Sigstore-signed, which
does not satisfy Windows SmartScreen — so downloaded connector executables
(e.g. baton-active-directory) trigger SmartScreen warnings (CE-424).

Add Authenticode signing to the goreleaser-windows job using Azure Trusted
Signing (CE-178), gated behind a new windows_authenticode_signing input
(default false) so existing releases are unaffected until the Azure account
is provisioned.

When enabled, the job:
- logs in to Azure via GitHub Actions OIDC (no certificate material in secrets)
- installs the Microsoft `sign` CLI
- signs the raw .exe in a GoReleaser build post-hook, before it is packaged,
  so the binary in both the .zip and the .msi is signed
- signs the .msi in place via a GoReleaser signs entry ordered ahead of the
  cosign signature, so the Sigstore bundle and all downstream hashes cover the
  Authenticode-signed bytes

Signing logic lives in scripts/sign-windows-authenticode.ps1, which calls
`sign code trusted-signing` and verifies the result. New optional inputs
(trusted_signing_*) and secrets (AZURE_CLIENT_ID/TENANT_ID/SUBSCRIPTION_ID)
are validated up front. README and release-workflow docs updated.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@c1-squire-dev
c1-squire-dev Bot requested a review from a team June 23, 2026 15:45
@linear-code

linear-code Bot commented Jun 23, 2026

Copy link
Copy Markdown

CE-424

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant