Die Code-Signierung hat ein Problem mit der Schlüsselverwaltung. Beim üblichen Vorgehen wird eine .pfx-Datei kopiert oder ein USB-Token eingesteckt, und zwar auf jeden Build-Agenten, der ein Release signieren muss. Der private Schlüssel landet auf Maschinen, die nicht vertrauenswürdige Build-Skripte ausführen, es gibt keine Aufzeichnung darüber, was von wem signiert wurde, und das Rotieren des Zertifikats bedeutet, jeden Agenten anfassen zu müssen. sgcSign 2026.6 beantwortet das mit einem neuen Signierserver: einem selbstgehosteten Dienst, der die Signierung über eine TLS-REST-API bereitstellt, sodass Ihre Pipelines und Entwickler remote signieren, während der Signierschlüssel an genau einem Ort verbleibt.
Der Schlüssel verlässt niemals den Server. Noch besser: Der Server kann einem Hardware-Token oder einem Cloud-KMS vorgeschaltet werden, sodass der Schlüssel überhaupt nicht als Datei existiert. Jede Anfrage wird mit einem API-Schlüssel authentifiziert, ratenbegrenzt und in ein manipulationssicheres Audit-Log geschrieben. Dieser Beitrag behandelt, was der Server signieren kann, wie man ihn konfiguriert, einen Schnellstart in fünf Minuten und die zwei Wege, ihn aufzurufen: einfaches curl und der mitgelieferte sgcsign-Befehlszeilen-Client.
Was er signiert
Ein Server, eine API, acht Signaturformate. Dieselbe Endpunktform (POST /api/v1/sign/<format>) deckt sowohl ausführbare Dateien als auch Dokumente ab:
- Authenticode — Windows-PE-Dateien:
.exe,.dll,.sys,.msi,.cab,.ocx. Optionale doppelte SHA-1- + SHA-256-Signierung für ältere Windows-Versionen. - PAdES — PDF-Dokumente, mit Grund, Ort, Kontakt und Name des Unterzeichners.
- XAdES — XML, enveloped, enveloping oder detached, mit länderspezifischen E-Invoicing-Profilen wie eIDAS, FacturaE, FatturaPA, KSeF, Peppol, VeriFactu und TicketBAI.
- CAdES — detached PKCS#7 (
.p7s) über beliebige Nutzdaten. - ClickOnce — Anwendungs- und Deployment-Manifeste.
- NuGet — Signierung von
.nupkg-Paketen. - VSIX — Visual-Studio-Erweiterungspakete.
- PowerShell —
.ps1- /.psm1- /.psd1-Skripte (Authenticode SIP).
Jedes Format akzeptiert eine optionale RFC-3161-Zeitstempel-URL, sodass Signaturen auch nach Ablauf des Signierzertifikats gültig bleiben. Ein begleitender POST /api/v1/verify-Endpunkt prüft eine vorhandene Signatur und gibt den Betreff des Unterzeichners, die Gültigkeit und den Zeitstempel zurück.
Einsetzbare Schlüsselanbieter
Ein Anbieter ist eine benannte Referenz auf einen Signierschlüssel. Der Aufrufer nennt bei jeder Anfrage einen Anbieter; er sieht den Schlüssel nie. Sie können so viele registrieren, wie Sie benötigen, und derselbe Server kann eine lokale PFX für interne Werkzeuge mit einem Cloud-gestützten EV-Zertifikat für öffentliche Releases mischen. Neun Anbietertypen werden unterstützt:
- Windows Certificate Store (
WinCertStore) — wählt ein Zertifikat über Fingerabdruck oder Betreff aus, ideal für EV-Zertifikate, die auf einem Token registriert sind. - PFX und PEM — Zertifikats- und Schlüsseldateien auf der Festplatte.
- PKCS#11 / HSM (
PKCS11) — Hardware-Token wie YubiKey oder ein Netzwerk-HSM. - AWS KMS, Azure Trusted Signing, Google Cloud KMS, HashiCorp Vault und Certum SimplySign — der private Schlüssel liegt im Cloud-Dienst und erreicht den Server nie.
Geheimnisse bleiben aus der Konfigurationsdatei heraus. Jeder Parameter, dessen Name auf _env endet, wird aus einer Umgebungsvariable gelesen, sodass das PFX-Passwort, die Token-PIN oder das Cloud-Secret von der Dienstumgebung bereitgestellt und nicht auf die Festplatte committet wird.
Den Server konfigurieren
Der gesamte Server wird durch eine einzige JSON-Datei gesteuert, sgcSignServer.conf.json (ein dokumentiertes Beispiel wird als sgcSignServer.conf.sample.json mitgeliefert). Die oberste Struktur besteht aus einer Handvoll Blöcke:
{
"server": {
"listen": "0.0.0.0",
"port": 8443,
"tls": {
"enabled": true,
"cert_file": "certs/server.crt",
"key_file": "certs/server.key"
},
"max_upload_mb": 512,
"firewall": {
"enabled": true,
"whitelist": ["10.0.0.0/8"],
"brute_force": { "enabled": true, "max_attempts": 5, "ban_duration_sec": 900 },
"rate_limit": { "enabled": true, "max_connections_per_ip": 30, "time_window_sec": 60 }
}
},
"storage": { "sqlite_path": "data/sgcsignserver.db" },
"admin": {
"initial_user": "admin",
"initial_password_env": "SGCSIGN_ADMIN_INIT_PW",
"session_timeout_minutes": 60
},
"audit": { "retention_days": 365 },
"providers": [
{
"name": "pfx-build",
"type": "PFX",
"params": { "file": "certs/build.pfx", "password_env": "SGCSIGN_PFX_PW" }
},
{
"name": "ev-release",
"type": "AzureTS",
"params": {
"tenant_id": "00000000-0000-0000-0000-000000000000",
"client_id": "00000000-0000-0000-0000-000000000000",
"client_secret_env": "SGCSIGN_AZURE_TS_SECRET",
"account": "your-account",
"certificate_profile": "your-profile",
"endpoint": "https://eus.codesigning.azure.net/"
}
}
]
}
Die Blöcke bilden direkt die Funktionen ab. server legt die Bind-Adresse, den Port (standardmäßig 8443), das TLS-Zertifikat und die eingebaute Firewall fest (IP-Erlaubnis- und Sperrlisten, Brute-Force-Sperre, Verbindungsratenbegrenzung, Path-Traversal- und Nutzdaten-Schutzvorrichtungen). storage verweist auf die SQLite-Datenbank, die Benutzer, API-Schlüssel, das Audit-Log und die Webhook-Warteschlange enthält. admin definiert den ersten Benutzer und wie lange Sitzungen dauern. audit legt das Aufbewahrungsfenster fest. providers ist die Liste von oben.
Das Bootstrap-Admin-Passwort wird nie in der Datei gespeichert. Beim allerersten Start, wenn die Benutzertabelle leer ist, liest der Server die durch initial_password_env benannte Umgebungsvariable (standardmäßig SGCSIGN_ADMIN_INIT_PW) und erstellt das Admin-Konto. Bei jedem späteren Start wird diese Variable ignoriert, sodass sie ausschließlich den ersten Login initialisiert.
Schnellstart in fünf Minuten
Installieren Sie den Server (der Setup-Assistent registriert den Windows-Dienst, oder führen Sie sgcSignServer.exe --install aus), dann:
1. Erstellen Sie ein Test-Code-Signing-Zertifikat und exportieren Sie es als PFX. Für ein echtes Deployment importieren Sie Ihr von der CA ausgestelltes Zertifikat, oder Sie überspringen dies und richten stattdessen einen Anbieter auf Ihren Token oder Ihr Cloud-KMS aus.
$cert = New-SelfSignedCertificate -Type CodeSigningCert `
-Subject "CN=sgcSign Quickstart" -KeyAlgorithm RSA -KeyLength 3072 `
-CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(1)
$pw = ConvertTo-SecureString "QuickStartPFX!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -Password $pw `
-FilePath "C:\Program Files\sgcSign Server\certs\quickstart.pfx"
2. Setzen Sie die Geheimnisse als Maschinen-Umgebungsvariablen, damit das Dienstkonto sie lesen kann:
setx /M SGCSIGN_ADMIN_INIT_PW "ChangeMeNow!"
setx /M SGCSIGN_PFX_PW "QuickStartPFX!"
3. Schreiben Sie eine minimale Konfiguration mit einem PFX-Anbieter (TLS nur für einen localhost-Test deaktiviert):
{
"server": { "listen": "127.0.0.1", "port": 8443, "tls": { "enabled": false } },
"storage": { "sqlite_path": "data/sgcsignserver.db" },
"admin": { "initial_user": "admin", "initial_password_env": "SGCSIGN_ADMIN_INIT_PW" },
"audit": { "retention_days": 365 },
"providers": [
{ "name": "pfx-quickstart", "type": "PFX",
"params": { "file": "certs/quickstart.pfx", "password_env": "SGCSIGN_PFX_PW" } }
]
}
4. Starten Sie den Dienst und bestätigen Sie, dass er lauscht:
sc start sgcSignServer
sc query sgcSignServer
Falls er beim Start stoppt, führen Sie ihn im Vordergrund mit sgcSignServer.exe --console --config <path> aus, um den Fehler live zu sehen (eine fehlende SGCSIGN_ADMIN_INIT_PW oder eine nicht lesbare PFX sind die üblichen Ursachen). Das Flag --selftest-providers lädt die Konfiguration, initialisiert jeden Anbieter und beendet sich, sodass Sie Schlüssel validieren können, bevor Sie produktiv gehen.
5. Melden Sie sich an und erstellen Sie einen API-Schlüssel. Öffnen Sie http://localhost:8443/admin, melden Sie sich als admin mit dem Bootstrap-Passwort an und erstellen Sie einen API-Schlüssel. Der Klartextschlüssel wird bei der Erstellung einmalig angezeigt; kopieren Sie ihn sofort. Schlüssel tragen das Präfix sgcsk_.
6. Signieren Sie eine ausführbare Testdatei mit curl:
curl -X POST http://localhost:8443/api/v1/sign/authenticode ^
-H "X-API-Key: sgcsk_..." ^
-F file=@app.exe ^
-F provider=pfx-quickstart ^
-F hash=sha256 ^
--output app-signed.exe
Das ist der gesamte Ablauf: einen Anbieter konfigurieren, einen Schlüssel ausstellen, signieren. Von hier aus tauschen Sie die selbstsignierte PFX gegen ein echtes Zertifikat aus, schalten TLS ein und sperren die Firewall auf Ihr CI-Subnetz ein.
Signieren über REST
Jede Signieranfrage ist ein POST mit der Datei und ein paar Formularfeldern. Die Authentifizierung erfolgt über einen Header, entweder X-API-Key: sgcsk_... oder Authorization: Bearer sgcsk_.... Die Antwort ist das signierte Artefakt als application/octet-stream, wobei der Betreff des Unterzeichners und die Signierdauer in den Headern X-Sgcsign-Signer-Subject und X-Sgcsign-Duration-Ms zurückgegeben werden.
Signieren einer PDF, mit einem sichtbaren Signaturgrund und -ort:
curl -X POST https://sign.acme.local:8443/api/v1/sign/pades \
-H "X-API-Key: sgcsk_..." \
-F file=@invoice.pdf \
-F provider=qualified-eu \
-F tsa_url=http://timestamp.digicert.com \
-F reason=Approved \
-F location="Madrid, Spain" \
-F signer_name="Acme Billing" \
-o invoice-signed.pdf
Signieren einer XML-Rechnung mit einem eIDAS-XAdES-Profil:
curl -X POST https://sign.acme.local:8443/api/v1/sign/xades \
-H "X-API-Key: sgcsk_..." \
-F file=@invoice.xml \
-F provider=qualified-eu \
-F profile=eidas \
-F xades_type=enveloped \
-o invoice-signed.xml
Das Verifizieren einer Signatur gibt JSON statt einer Datei zurück:
curl -X POST https://sign.acme.local:8443/api/v1/verify \
-H "X-API-Key: sgcsk_..." \
-F file=@app-signed.exe \
-F format=authenticode
{ "valid": true, "status": "valid",
"subject": "CN=Acme Inc., O=Acme, C=US",
"has_timestamp": true, "timestamp_time": "2026-06-15T13:01:17.000Z" }
Der sgcsign-Befehlszeilen-Client
Der Server wird mit sgcsign ausgeliefert, einer kleinen formatübergreifenden CLI mit vier Verben: sign, verify, keys und health. Die Server-URL, der API-Schlüssel und der Anbieter können aus Flags oder aus den Umgebungsvariablen SGCSIGN_SERVER, SGCSIGN_APIKEY und SGCSIGN_PROVIDER stammen, was Geheimnisse in der CI von der Befehlszeile fernhält:
set SGCSIGN_SERVER=https://sign.acme.local:8443
set SGCSIGN_APIKEY=sgcsk_...
sgcsign sign -f authenticode -p pfx-build -o app-signed.exe app.exe ^
--tsa http://timestamp.digicert.com --desc "Acme Installer"
sgcsign verify -f authenticode app-signed.exe
Für Authenticode gibt es einen bandbreitensparenden Trick. Im Pre-Hash-Modus (--prehash, standardmäßig aktiviert) berechnet die CLI den PE-Hash lokal und lädt nur den Hash hoch, ein paar hundert Byte statt einer mehrere Megabyte großen Binärdatei. Der Server signiert den Hash und gibt einen detached PKCS#7-Blob zurück, den der Client in die Datei einbettet. Auf einem bandbreitenbeschränkten CI-Agenten, der einen großen Installer signiert, wird so aus einem Mehr-Megabyte-Upload ein winziger.
Sicherheit und Betrieb
Der Server ist darauf ausgelegt, unbeaufsichtigt vor einem echten Signierschlüssel zu laufen, daher zählt die operative Oberfläche genauso viel wie die Kryptografie:
- Admin-Konsole unter
/admin: Dashboard, API-Schlüssel, Anbieter, Benutzer, Projekte und der Audit-Trail, alles im Browser. - API-Schlüssel mit Ratenbegrenzungen pro Schlüssel und Tageskontingenten. Ein Schlüssel, der sein Limit erreicht, erhält
429mit einemRetry-After-Header. - Mandantenfähige Projekte, sodass ein auf ein Team beschränkter Schlüssel nicht die Anbieter eines anderen Teams nutzen kann.
- Freigabe-Workflow (optional): ein zweistufiger Ablauf, bei dem eine Signieranfrage zurückgehalten wird, bis ein Operator sie freigibt, für hochwertige Release-Zertifikate.
- Manipulationssicheres Audit-Log: jede Signierung, Verifizierung, jeder Login und jede Konfigurationsänderung wird per Hash verkettet, sodass die Aufzeichnung im Nachhinein nicht verändert werden kann.
- Prometheus-Metriken unter
/api/v1/metricsund Liveness-/Readiness-Probes unter/api/v1/health, bereit für Ihren Monitoring-Stack. - Ausgehende Webhooks, die bei jeder Signieroperation ein JSON-Event per POST senden, um die Signierung in Slack, ein SIEM oder ein Release-Dashboard einzubinden.
- OpenAPI-3.1-Spezifikation unter
/api/v1/openapi.jsonmit einer interaktiven Swagger-UI unter/api/v1/docs. - TLS 1.2+ mit optionaler ACME- / Let's-Encrypt-Challenge-Bereitstellung, plus der eingebauten Firewall für IP-Filterung und Missbrauchsschutz.
Warum selbst hosten
Der Sinn des Servers besteht darin, eine Flotte riskanter, schlüsseltragender Build-Agenten auf einen einzigen gehärteten Endpunkt zu reduzieren. Der Signierschlüssel liegt nur auf dem Server, oder im HSM oder Cloud-KMS, dem der Server vorgeschaltet ist, niemals auf den Maschinen, die Ihre Build-Skripte ausführen. Der Zugriff wird durch API-Token pro Schlüssel mit Kontingenten geregelt, auf Projekte beschränkt, und jede Signatur wird in einem Audit-Log festgehalten, das Sie kontrollieren. Das Rotieren eines Zertifikats, das Widerrufen des Schlüssels eines kompromittierten Agenten oder der Nachweis, wer was signiert hat, werden alle zu einem einzigen Ort, an dem man nachschaut, statt zu vielen.
Verfügbarkeit
Der sgcSign Server ist Teil von sgcSign 2026.6.0. Er läuft als Windows-Dienst oder als Konsolenanwendung, wird durch die oben gezeigte einzelne JSON-Datei konfiguriert und über curl, die mitgelieferte sgcsign-CLI oder jeden HTTP-Client über seine OpenAPI-Beschreibung gesteuert.
Fragen, Feedback oder Hilfe bei der Einrichtung? Nehmen Sie Kontakt auf. Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.
