Batch poster: External signing (KMS)
Nitro's batch poster (and staker) sign their L1 transaction through the DataPoster component. By default it signs locally with a private key, but it also supports generic RPC-based external signing: instead of holding the key, Nitro sends an unsigned transaction to a remote signer over (m)TLS, gets back a signed transaction, and independently verifies it.
There is no native AWS KMS integration in the Nitro codebase. KMS support is achieved by running a separate signer service that talks to KMS and exposes an Ethereum-style eth_signTransaction RPC endpoint. Nitro connects to that endpoint. In other words: "KMS support" = external signer pointed at a KMS-backed signing service.
How it works internally
- Connect—
rpcClient()dials the signer URL with a TLS config: optional client cert/key for mTLS (ClientCert/ClientPrivateKey), optionalRootCA(lets you use self-signed certs), andInsecureSkipVerify. - Sign—
externalSigner()returns a signer callback that:
- Converts the transaction to
apitypes.SendTxArgsviaTxToSignTxArgs- Note that it fully supports EIP-4844 blob transactions (blobs, commitments, proofs), which the batch poster needs.
- Calls the configured RPC method:
client.CallContext(ctx, &data, opts.Method, args), expecting an RLP-encoded signed transaction back. - Verifies the returned transaction: the hash must match the request and the recovered sender must equal the configured
Address. This means TLS is not relied on for authentication—the signature itself is checked at the application layer.
Configuration
The config struct is ExternalSignerCfg:
| Field | koanf key | Purpose |
|---|---|---|
URL | url | RPC endpoint of the signer. Setting this enables external signing (overrides local key). |
Address | address | Hex Ethereum address the signer controls; used to verify returned signatures. |
Method | method | RPC method name, e.g., eth_signTransaction. |
RootCA | root-ca | (Optional) CA cert to trust — enables self-signed server certs. |
ClientCert | client-cert | (Optional) client cert for mTLS. |
ClientPrivateKey | client-private-key | (Optional) client key for mTLS (required if client-cert set). |
InsecureSkipVerify | insecure-skip-verify | Skip server TLS verification (not recommended). |
This config is nested under both the batch poster and the staker. So the full CLI flag paths are:
Batch poster:
--node.batch-poster.data-poster.external-signer.url
--node.batch-poster.data-poster.external-signer.address
--node.batch-poster.data-poster.external-signer.method
--node.batch-poster.data-poster.external-signer.root-ca
--node.batch-poster.data-poster.external-signer.client-cert
--node.batch-poster.data-poster.external-signer.client-private-key
--node.batch-poster.data-poster.external-signer.insecure-skip-verify
Staker uses the same fields under --node.staker.data-poster.external-signer.*
When external-signer.url is empty, the batch poster requires a local key. The check in cmd/nitro/nitro.go confirms this—and note that AnyTrust mode still needs a local key (external signing isn't supported alongside AnyTrust there).
What the signer service must implement
Your signer (whether KMS-backed or otherwise) must expose an HTTPS RPC server with a method matching Method, that:
- Accepts an Ethereum transaction object (
apitypes.SendTxArgs—the standardeth_signTransactionshape, including blob fields for EIP-4844), - Returns the RLP-encoded signed transaction as a hex string,
- Signs with the key for the address you configured as
address.
If you use mTLS, the server must require and verify the client cert that matches client-cert/client-private-key.
Reference implementations
Nitro ships two working examples you can model a KMS service on:
cmd/mockexternalsigner/mockexternalsigner.go—a standalone signer binary. It builds anrpc.Server, registers a signing method, serves over HTTPS withtls.RequireAndVerifyClientCert, and prints the exact flags to pass to Nitro. Swap the local-keytxOpts.Signerfor a KMS-backed signer and you have a KMS integration.arbnode/dataposter/externalsignertest/externalsignertest.go—the test harness, showing the server side (SignerAPI, method registration, cert setup withRequireAndVerifyClientCert). The RPC method (externalsignertest.go:185) takes*apitypes.SendTxArgsand returns the RLP-encoded signed tx ashexutil.Bytes.