Summary
Allow the remote payment signer (-remoteSigner) to use an external key-custody / remote-signing backend (e.g. Turnkey, AWS KMS, GCP KMS, clef) instead of only a local keystore, behind a pluggable signing interface.
Motivation
The remote signer holds an Ethereum hot key to sign PM tickets and to fund on-chain deposit/reserve. Today that key is a local keystore on the signer host. For a shared, pooled-wallet payment signer that is the single biggest risk: compromise the host and the deposit/reserve can be drained, and there are no wallet-level spend controls.
Proposal
Make the signing path pluggable and add one external-signer client that speaks a standard remote-signing protocol, rather than integrating each provider. Backends then sit behind that protocol, outside go-livepeer:
- Port (in go-livepeer): a standard external-signer client, e.g. go-ethereum's
accounts/external (clef JSON-RPC) or a Web3Signer-compatible API.
- Adapters (outside go-livepeer): Turnkey, AWS KMS, GCP KMS, HashiCorp Vault, HSM. Web3Signer already ships plugins for KMS/Vault/HSM; others reach the port via a thin shim. Adding a backend means running a sidecar/config change, no go-livepeer change.
The key never leaves the enclave/KMS; the signer asks the backend to sign:
- PM ticket payloads (raw secp256k1 message signing)
- State-blob and orchestrator-info signatures
- On-chain transactions (
fundDeposit / fundReserve / withdraw) — go-livepeer still builds the tx (nonce, gas) and broadcasts via its own RPC; the backend only returns a signature.
Note: providers like Turnkey are wallet / key-management infrastructure (enclave-secured keys), not a "signer" product. The overloaded term here is go-livepeer's -remoteSigner; the external signer is the key backend.
Integration point (current code)
Signing already goes through a clean interface, so this is additive, not surgery:
pm.Signer (pm/signer.go): Sign(msg []byte) ([]byte, error) + Account() accounts.Account.
eth.AccountManager (eth/accountmanager.go) is the only implementation today and wraps a local go-ethereum keystore.KeyStore (Sign, SignTypedData, Unlock).
server/remote_signer.go only ever signs via these interfaces (Eth.Sign(...)), never a raw key.
So the work is an alternative AccountManager/Signer implementation backed by the external client, plus a flag to select it. remote_signer.go itself does not change.
Benefits for payment signers
- No hot key on the signer host. The pooled wallet key lives in the enclave/KMS, removing the worst failure mode of running a shared payment signer.
- Policy-based loss prevention. Providers like Turnkey enforce signing policies (max value per period, allowlisted recipients/contracts, quorum on withdrawals) — i.e. anti-drain on deposit/reserve at the key layer, even if the signer is compromised.
- Safer HA / redundancy. Run redundant signers without copying a raw private key to each host.
- No protocol change. Tickets, deposit/reserve, redemption, and the gateway→orchestrator flow stay byte-identical. Only how a signature is produced changes.
Scope / considerations
- Implement behind the existing
pm.Signer / AccountManager interface so the backend (local keystore vs Turnkey/KMS/HSM) is a swappable adapter.
- Raw-hash signing: PM tickets are signed as a raw keccak hash. Some remote signers refuse raw-hash signing for safety, so the chosen interface must allow it (clef
account_signData and Web3Signer eth1 modes can) — verify against the ticket format.
- Hot-path latency + cost: PM mints tickets frequently, so per-signature API round-trips add latency and cost vs a local key. Worth measuring against minting rate; batch/cached signing may be needed.
- This is cleanly enabled by factoring the signer into a standalone package, but can land as a contained adapter on the current
-remoteSigner mode.
Out of scope
- Per-user / embedded wallets (a larger non-custodial direction) — separate discussion.
- Clearinghouse / accounting changes — none required; this sits below the signer seam.
Note
Idea originally raised by @eliteprox.
Summary
Allow the remote payment signer (
-remoteSigner) to use an external key-custody / remote-signing backend (e.g. Turnkey, AWS KMS, GCP KMS, clef) instead of only a local keystore, behind a pluggable signing interface.Motivation
The remote signer holds an Ethereum hot key to sign PM tickets and to fund on-chain deposit/reserve. Today that key is a local keystore on the signer host. For a shared, pooled-wallet payment signer that is the single biggest risk: compromise the host and the deposit/reserve can be drained, and there are no wallet-level spend controls.
Proposal
Make the signing path pluggable and add one external-signer client that speaks a standard remote-signing protocol, rather than integrating each provider. Backends then sit behind that protocol, outside go-livepeer:
accounts/external(clef JSON-RPC) or a Web3Signer-compatible API.The key never leaves the enclave/KMS; the signer asks the backend to sign:
fundDeposit/fundReserve/withdraw) — go-livepeer still builds the tx (nonce, gas) and broadcasts via its own RPC; the backend only returns a signature.Integration point (current code)
Signing already goes through a clean interface, so this is additive, not surgery:
pm.Signer(pm/signer.go):Sign(msg []byte) ([]byte, error)+Account() accounts.Account.eth.AccountManager(eth/accountmanager.go) is the only implementation today and wraps a local go-ethereumkeystore.KeyStore(Sign,SignTypedData,Unlock).server/remote_signer.goonly ever signs via these interfaces (Eth.Sign(...)), never a raw key.So the work is an alternative
AccountManager/Signerimplementation backed by the external client, plus a flag to select it.remote_signer.goitself does not change.Benefits for payment signers
Scope / considerations
pm.Signer/AccountManagerinterface so the backend (local keystore vs Turnkey/KMS/HSM) is a swappable adapter.account_signDataand Web3Signer eth1 modes can) — verify against the ticket format.-remoteSignermode.Out of scope