livepeer / livepeer/go-livepeer

Support external key custody / remote signing (Turnkey, KMS) for payment signers

Open
#3,941 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

payments
Dominant language
Go
Stars
586
Forks
226
Avg merge
1d 17h
Merged PRs (30d)
19

Description

[!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:

  • 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with pm/signer.go and eth/accountmanager.go to understand the existing signing interfaces, then trace their use from server/remote_signer.go. Compare the proposed external-signing protocols and verify how PM ticket, state-blob, orchestrator-info, and transaction signatures must be represented. Done means an external-signer implementation and selection mechanism work through the existing interfaces without requiring changes to remote_signer.go.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, blockchain, payments, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.