- services/signing-service/pkg/httpapi exposes NewTestHandler so sibling modules can build the real signing-service in-process (same pattern transparency-log already uses). - services/admin-api/internal/attest/interop_signing_test.go drives the real attest.HTTPSigner against the real signing-service handler and asserts the end-to-end ADR-0005 round-trip: envelope shape, keyid, content_hash self-consistency across canonicalisers, Ed25519 signature verification with the server's public key, and canonical-payload byte equality. Closes the "Interop-Test: admin-api attest.HTTPSigner-Client erfolgreich gegen diesen Server" acceptance criterion from DEV-599. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|---|---|---|
| .. | ||
| cmd/signing-service | ||
| internal | ||
| pkg/httpapi | ||
| go.mod | ||
| README.md | ||
signing-service
HTTP service that implements POST /api/v1/sign/dsse per
ADR-0005. It
canonicalises an in-toto v1 Statement, DSSE-signs it with the key named by
key_ref, and returns the envelope plus a stable content_hash that the
admin-api and other clients use as the single attestation reference.
Status
- Signing is real: Ed25519 PAE + envelope + content_hash. Verified
end-to-end against the admin-api
attest.HTTPSignerclient via a Go interop test that re-verifies the signature with the server's public key. - In-memory keyring:
-backend=memory. Ephemeral keys are generated at startup unless-keys-from-envis set; stable dev keys can be supplied as hex-encoded 64-byte Ed25519 private keys viaKEY_<slug>env vars. - OpenBao Transit backend: stub (
-backend=openbaoreturnsErrNotWired). Separate subtask. - Pocket ID JWKS verifier: stub. Dev uses the static
-bearerstable. Separate subtask. - OPA policy decider: stub. Dev uses AllowAll. Separate subtask.
- Deployment manifest: separate subtask.
Layout
services/signing-service/
├── README.md
├── go.mod
├── cmd/signing-service/main.go — HTTP entry (bind + router + graceful shutdown)
└── internal/
├── canonical/canonical.go — stable JSON serialisation (byte-for-byte
│ compatible with admin-api/internal/attest/hash.go)
├── signer/signer.go — Signer interface, InMemory (Ed25519), OpenBao stub,
│ DSSE PAE and SignStatement orchestration
├── signer/signer_test.go — signature verification, PAE format exactness, errors
├── policy/policy.go — Decider interface, AllowAll, OPA stub
├── token/validator.go — bearer validator, Static + PocketID stub
└── httpapi/
├── sign.go — POST /api/v1/sign/dsse handler + /healthz
└── sign_test.go — happy path, auth, policy, unknown key, bad statement
Local dev
cd services/signing-service
go vet ./... && go test ./...
go run ./cmd/signing-service \
-listen=:8081 \
-backend=memory \
-keys=trust-api/rate-change-signer-2026-q4 \
-bearers=dev-token=agent-admin-api
Smoke-test it with curl:
curl -sS -X POST http://localhost:8081/api/v1/sign/dsse \
-H "Authorization: Bearer dev-token" \
-H "Content-Type: application/json" \
-d '{
"key_ref":"trust-api/rate-change-signer-2026-q4",
"statement":{
"_type":"https://in-toto.io/Statement/v1",
"subject":[{"name":"per_diem_rate/PDR-1","digest":{"sha256":"aaaa"}}],
"predicateType":"https://basicstack.de/attestations/rate_change/v1",
"predicate":{"change_kind":"create","rate_id":"PDR-1"}
}
}' | jq .
Pointing the admin-api at this instance:
# Terminal 1
cd services/signing-service && go run ./cmd/signing-service -listen=:8081
# Terminal 2 (admin-api still needs a tlog, so this will log "attestation failed"
# until services/transparency-log is up — rows will still be created and marked
# attestation-pending as designed):
cd services/admin-api && go run ./cmd/admin-api -store=memory \
-signer-url=http://localhost:8081 \
-tlog-url=http://localhost:9099 \
-bearer=dev-token \
-signer-key=trust-api/rate-change-signer-2026-q4
Keys
Generate one hex-encoded Ed25519 private key for dev
go run ./cmd/signing-service -gen-dev-key
# → prints 128 hex chars (64 bytes raw private key)
Supply it via env:
# For key_ref "trust-api/rate-change-signer-2026-q4" the env name is
# KEY_TRUST_API_RATE_CHANGE_SIGNER_2026_Q4 (upper-case, / - . → _)
export KEY_TRUST_API_RATE_CHANGE_SIGNER_2026_Q4=<hex>
go run ./cmd/signing-service -backend=memory -keys-from-env \
-keys=trust-api/rate-change-signer-2026-q4
Prod
Prod wiring in the OpenBao-Transit subtask: Signer backend becomes
signer.OpenBao with HTTP client to the cluster-internal OpenBao, policy
backend becomes policy.OPA with the Rego bundle under policies/signing/
(not yet created), token validator becomes token.PocketID with JWKS from
https://auth.basicstack.de/.well-known/jwks.json.