sgcSign Server: samodzielnie hostowane podpisywanie kodu i dokumentów przez REST

· Komponenty

Podpisywanie kodu ma problem z zarządzaniem kluczami. Typowa konfiguracja kopiuje plik .pfx lub podłącza token USB do każdego agenta kompilacji, który musi podpisać wydanie. Klucz prywatny trafia na maszyny uruchamiające niezaufane skrypty kompilacji, nie ma żadnego zapisu tego, co zostało podpisane i przez kogo, a rotacja certyfikatu oznacza ingerencję w każdego agenta. sgcSign 2026.6 odpowiada na to nowym serwerem podpisującym: samodzielnie hostowanym demonem, który udostępnia podpisywanie przez REST API z TLS, dzięki czemu Twoje potoki i deweloperzy podpisują zdalnie, a klucz podpisujący pozostaje w dokładnie jednym miejscu.

Klucz nigdy nie opuszcza serwera. Co więcej, serwer może obsługiwać token sprzętowy lub chmurowy KMS, dzięki czemu klucz w ogóle nie istnieje jako plik. Każde żądanie jest uwierzytelniane kluczem API, ograniczane szybkością i zapisywane w dzienniku audytu odpornym na manipulacje. Ten wpis opisuje, co serwer może podpisać, jak go skonfigurować, pięciominutowy szybki start oraz dwa sposoby jego wywołania: zwykły curl oraz dołączony klient wiersza poleceń sgcsign.

Co podpisuje

Jeden serwer, jedno API, osiem formatów podpisu. Ten sam kształt punktu końcowego (POST /api/v1/sign/<format>) obejmuje zarówno pliki wykonywalne, jak i dokumenty:

Każdy format akceptuje opcjonalny adres URL znacznika czasu RFC 3161, dzięki czemu podpisy pozostają ważne po wygaśnięciu certyfikatu podpisującego. Towarzyszący punkt końcowy POST /api/v1/verify sprawdza istniejący podpis i zwraca podmiot podpisujący, ważność oraz znacznik czasu.

Wymienni dostawcy kluczy

Dostawca to nazwany uchwyt do klucza podpisującego. Wywołujący wskazuje dostawcę w każdym żądaniu; nigdy nie widzi klucza. Możesz zarejestrować ich tylu, ilu potrzebujesz, a ten sam serwer może łączyć lokalny PFX dla narzędzi wewnętrznych z certyfikatem EV opartym na chmurze dla wydań publicznych. Obsługiwanych jest dziewięć typów dostawców:

Sekrety pozostają poza plikiem konfiguracyjnym. Każdy parametr, którego nazwa kończy się na _env, jest odczytywany ze zmiennej środowiskowej, dzięki czemu hasło do PFX, kod PIN tokena lub sekret chmurowy są dostarczane przez środowisko usługi, a nie zapisywane na dysku.

Konfigurowanie serwera

Cały serwer jest sterowany jednym plikiem JSON, sgcSignServer.conf.json (udokumentowana próbka jest dołączona jako sgcSignServer.conf.sample.json). Najwyższy poziom struktury to kilka bloków:

{
  "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/"
      }
    }
  ]
}

Bloki bezpośrednio odpowiadają funkcjom. server ustawia adres powiązania, port (domyślnie 8443), certyfikat TLS i wbudowaną zaporę (listy zezwoleń i odmów IP, blokadę przy atakach brute-force, ograniczanie szybkości połączeń, zabezpieczenia przed przechodzeniem ścieżek i ładunkiem). storage wskazuje na bazę danych SQLite przechowującą użytkowników, klucze API, dziennik audytu i kolejkę webhooków. admin definiuje pierwszego użytkownika i czas trwania sesji. audit ustawia okno przechowywania. providers to powyższa lista.

Początkowe hasło administratora nigdy nie jest przechowywane w pliku. Przy pierwszym uruchomieniu, gdy tabela użytkowników jest pusta, serwer odczytuje zmienną środowiskową wskazaną przez initial_password_env (domyślnie SGCSIGN_ADMIN_INIT_PW) i tworzy konto administratora. Przy każdym kolejnym uruchomieniu ta zmienna jest ignorowana, więc inicjuje tylko pierwsze logowanie.

Szybki start w pięć minut

Zainstaluj serwer (kreator instalacji rejestruje usługę Windows lub uruchom sgcSignServer.exe --install), a następnie:

1. Utwórz testowy certyfikat do podpisywania kodu i wyeksportuj go jako PFX. W przypadku rzeczywistego wdrożenia importujesz certyfikat wydany przez Twój urząd CA lub pomijasz ten krok i zamiast tego wskazujesz dostawcy Twój token lub chmurowy KMS.

$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. Ustaw sekrety jako zmienne środowiskowe maszyny, aby konto usługi mogło je odczytać:

setx /M SGCSIGN_ADMIN_INIT_PW "ChangeMeNow!"
setx /M SGCSIGN_PFX_PW        "QuickStartPFX!"

3. Napisz minimalną konfigurację z jednym dostawcą PFX (TLS wyłączony tylko do testu na localhost):

{
  "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. Uruchom usługę i potwierdź, że nasłuchuje:

sc start sgcSignServer
sc query sgcSignServer

Jeśli zatrzymuje się przy uruchomieniu, uruchom go na pierwszym planie za pomocą sgcSignServer.exe --console --config <path>, aby zobaczyć błąd na żywo (brakujący SGCSIGN_ADMIN_INIT_PW lub nieczytelny PFX to zwykłe przyczyny). Flaga --selftest-providers ładuje konfigurację, inicjalizuje każdego dostawcę i kończy działanie, dzięki czemu możesz sprawdzić klucze przed wdrożeniem produkcyjnym.

5. Zaloguj się i utwórz klucz API. Otwórz http://localhost:8443/admin, zaloguj się jako admin początkowym hasłem i utwórz klucz API. Klucz w postaci jawnej jest pokazywany tylko raz przy tworzeniu; skopiuj go natychmiast. Klucze mają prefiks sgcsk_.

6. Podpisz testowy plik wykonywalny za pomocą 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

To cała pętla: skonfiguruj dostawcę, wydaj klucz, podpisz. Stąd zamieniasz samodzielnie podpisany PFX na rzeczywisty certyfikat, włączasz TLS i blokujesz zaporę do swojej podsieci CI.

Podpisywanie przez REST

Każde żądanie podpisania to POST z plikiem i kilkoma polami formularza. Uwierzytelnianie to jeden nagłówek, albo X-API-Key: sgcsk_..., albo Authorization: Bearer sgcsk_.... Odpowiedzią jest podpisany artefakt jako application/octet-stream, z podmiotem podpisującym i czasem trwania podpisywania zwracanymi w nagłówkach X-Sgcsign-Signer-Subject i X-Sgcsign-Duration-Ms.

Podpisywanie pliku PDF, z widocznym powodem i lokalizacją podpisu:

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

Podpisywanie faktury XML z profilem eIDAS XAdES:

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

Weryfikacja podpisu zwraca JSON, a nie plik:

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" }

Klient wiersza poleceń sgcsign

Serwer jest dostarczany z sgcsign, małym wieloformatowym CLI z czterema poleceniami: sign, verify, keys i health. Adres URL serwera, klucz API i dostawca mogą pochodzić z flag lub ze zmiennych środowiskowych SGCSIGN_SERVER, SGCSIGN_APIKEY i SGCSIGN_PROVIDER, co utrzymuje sekrety poza wierszem poleceń w CI:

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

W przypadku Authenticode istnieje sztuczka oszczędzająca przepustowość. W trybie wstępnego haszowania (--prehash, domyślnie włączony) CLI oblicza skrót PE lokalnie i przesyła tylko skrót, kilkaset bajtów zamiast wielomegabajtowego pliku binarnego. Serwer podpisuje skrót i zwraca odłączony blob PKCS#7, który klient osadza w pliku. Na agencie CI z ograniczoną przepustowością podpisującym duży instalator zamienia to wielomegabajtowe przesyłanie w niewielkie.

Bezpieczeństwo i operacje

Serwer jest zbudowany do działania bez nadzoru przed rzeczywistym kluczem podpisującym, więc powierzchnia operacyjna ma takie samo znaczenie jak kryptografia:

Dlaczego hostować samodzielnie

Celem serwera jest zredukowanie floty ryzykownych, posiadających klucze agentów kompilacji do jednego utwardzonego punktu końcowego. Klucz podpisujący znajduje się wyłącznie na serwerze lub w HSM albo chmurowym KMS, który serwer obsługuje, nigdy na maszynach uruchamiających Twoje skrypty kompilacji. Dostęp jest kontrolowany przez tokeny API przypisane do kluczy z przydziałami, ograniczone do projektów, a każdy podpis jest rejestrowany w dzienniku audytu, który kontrolujesz. Rotacja certyfikatu, unieważnienie klucza skompromitowanego agenta lub udowodnienie, kto co podpisał, stają się jednym miejscem do sprawdzenia zamiast wielu.

Dostępność

sgcSign Server jest częścią sgcSign 2026.6.0. Działa jako usługa Windows lub aplikacja konsolowa, jest konfigurowany pojedynczym plikiem JSON pokazanym powyżej i sterowany za pomocą curl, dołączonego CLI sgcsign lub dowolnego klienta HTTP poprzez jego opis OpenAPI.

Pytania, opinie lub pomoc w konfiguracji? Skontaktuj się. Otrzymasz odpowiedź od osób, które napisały kod.