ssign English version

Signature de code dans GitHub Actions avec Certum SimplySign

ssign tourne sur une machine Linux et y signe les binaires Windows : pas de machine Windows, pas de SimplySign Desktop, pas de conteneur. L'e-mail du compte et la graine TOTP viennent de secrets d'environnement.

Un workflow de signature

name: Sign

on:
  workflow_dispatch:        # manuel uniquement — chaque exécution signe réellement

jobs:
  sign:
    runs-on: ubuntu-latest
    environment: signing    # ← environnement protégé ; voir la section suivante
    steps:
      - uses: actions/checkout@v4
      - run: cargo install ssign
      - run: ssign dist/*.exe
        env:
          CERTUM_EMAIL: ${{ secrets.CERTUM_EMAIL }}
          CERTUM_OTP:   ${{ secrets.CERTUM_OTP }}
      - uses: actions/upload-artifact@v4
        with: { name: signed, path: dist/ }

CERTUM_OTP contient votre graine TOTP, le secret à longue durée qui permet de signer en votre nom. Stockez-la comme décrit ci-dessous, pas comme un simple secret de dépôt.

Exiger l'accord du propriétaire pour chaque signature

Signer engage votre certificat et, mal géré, peut exposer la graine. Verrouillez la signature derrière un Environment GitHub, pour que le propriétaire du dépôt approuve chaque exécution avant même que le job ne puisse lire les secrets :

  1. Settings → Environments → New environment, nommez-le signing.
  2. Ajoutez une règle Deployment protection rule → Required reviewers, et ajoutez-vous (le propriétaire). Tout job visant cet environnement se met en pause en attendant votre approbation.
  3. Stockez CERTUM_EMAIL et CERTUM_OTP comme secrets d'environnement de signing (pas des secrets de dépôt). Ils ne sont lisibles que dans une exécution approuvée d'un job qui déclare environment: signing.
  4. Dans le workflow, le job de signature déclare environment: signing, comme ci-dessus.

Résultat : une pull request, même malveillante, ne peut pas déclencher une signature ni lire la graine ; chaque exécution attend le clic du propriétaire. Gardez aussi le job de signature sur workflow_dispatch ou sur des pushes de branches protégées, jamais sur pull_request depuis un fork.

Dans un pipeline de publication

Faites de la signature un job du même workflow que la compilation et la publication, verrouillé par environment: signing, et que le job de publication liste dans needs:. Un tag devient alors compilation → approbation → version signée. Ne comptez pas sur un workflow séparé déclenché par release: published : une release créée par le GITHUB_TOKEN intégré ne déclenche pas d'autre workflow.

Un exemple réel : ssign signe sa propre version Windows

Le workflow de publication de ssign fait exactement cela. À chaque tag de version, un job sur ubuntu-latest reprend le binaire Linux ssign compilé plus tôt dans la même exécution, attend l'approbation via l'environnement signing, signe ssign.exe et ssign_pkcs11.dll pour Windows avec une seule connexion Certum, puis contrôle les deux avec osslsigncode verify. Le job de publication l'attend. Extrait :

  sign-windows:
    needs: build
    if: startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-latest
    environment: signing
    steps:
      # …download the Linux ssign and the Windows artifacts built earlier in the run…
      - name: Sign the Windows binary + module with ssign (via Certum)
        env:
          CERTUM_EMAIL: ${{ secrets.CERTUM_EMAIL }}
          CERTUM_OTP: ${{ secrets.CERTUM_OTP }}
        run: |
          unzip -o dl/ssign-windows-x86_64.zip -d dl
          unzip -o dl/ssign-pkcs11-windows-x86_64.zip -d dl
          # One Certum login signs both the CLI and the module.
          ssign --verbose \
            -n "ssign" -u "https://github.com/${{ github.repository }}" \
            dl/ssign.exe dl/ssign_pkcs11.dll

  release:
    needs: [build, sign-windows, sign-apple]

Le fichier complet : .github/workflows/ci.yml.

Plusieurs fichiers, une connexion

Passez tous les fichiers au même appel de ssign, comme ci-dessus : il se connecte une seule fois pour tout le lot. Si une étape suivante du même job signe d'autres formats avec le module PKCS#11, le module réutilise la session en cache au lieu de se reconnecter (voir le cache de session).