Signer Boundary
What the signer owns today, what changes when the production signer lands, and how operators recognize healthy versus failing signer behavior.
Signer Boundary
The signer is the only component allowed to perform private-key operations: certificate PDF signatures, blockchain transaction signatures, defensive certificate HMACs, and decryption of agent proof envelopes. Everything else in the platform consumes the signer as a service.
Current State: In-Process Test Signer
Local and CI stacks use the in-process test signer. It is not a custody boundary.
| Attribute | Value |
|---|---|
| Mode | SIGNER_MODE=test |
| Package | internal/adapters/signer/testsigner |
| Seed | TEST_SIGNER_SEED (shared by API and proof worker so HMAC verification is stable) |
| Capabilities | proof-envelope:v1 decryption, deterministic HMACs, RSA-backed PAdES signing, placeholder blockchain transaction signing |
| Trust | None — no remote custody, no durable key store, no approval workflow, no hardware backing |
Do not run production load against SIGNER_MODE=test. A dedicated signer
service is the production boundary.
Production Signer Contract
The dedicated signer exposes a small service-to-service API owned by the signer team. The expected surface:
| Endpoint | Purpose |
|---|---|
GET /v1/keys/{key_id} | Public key metadata, active version, allowed usages, certificate chain. |
POST /v1/sign/digest | Sign a prehashed PDF/certificate digest with an allowed key usage. |
POST /v1/sign/transaction | Sign a chain-specific transaction payload after policy validation. |
POST /v1/hmac and POST /v1/hmac/verify | Compute and verify defensive certificate HMACs. |
POST /v1/decrypt | Decrypt agent proof envelopes. |
Every request must carry tenant/organization context, an idempotency key when signing can be retried, and produce an immutable audit event capturing key id, key version, usage, caller, request hash, and result.
Operator Checks
| Symptom | First check |
|---|---|
WipeSignerFailures by operation | decrypt, hmac, hmac_verify, pades_sign, or receipt_sign — see Incident response. |
Proofs stuck in SIGNING | Signer reachability, SIGNER_MODE, mTLS material, key IDs, TSA URL. |
PAdES verification failures on /verify | TSA reachability and signer certificate chain (PAdES trust anchors). |
INVALID_HMAC on public verification | Signer key version drift between issue-time and verify-time. |
Production Readiness Inputs
The signer is externally blocked until the signer team provides the
following. Track these against adr/0001-remaining-backend-gaps.md item 2:
| Input | Owner |
|---|---|
| Remote signer protocol semantics | Signer team |
| mTLS material (client cert, CA) | Infra |
| Key IDs and rotation metadata | Signer team |
| Transaction signing behavior | Signer team |
| HMAC, decrypt, PAdES, TSA behavior | Signer team |
Until these are delivered, SIGNER_MODE=test remains the only working mode
and any certificate issued is dev/CI only.
Backend Integration Notes
When the production signer lands, the backend integration is already scaffolded:
- Domain services stay on
SecretsProvider,KeySignerProvider, andSignatureProviderports. - A remote signer adapter ships beside
testsigner. - PAdES public certificate retrieval moves from local self-signed into signer metadata.
- Signer contract tests pin HMAC, digest signing, transaction signing, and proof-envelope decryption to fixed test vectors.
- Non-test modes fail at startup unless the remote signer URL, auth, and trust roots are configured.
Operators do not need to change anything in the application database when the signer mode flips; the change is configuration only.