Skip to main content

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.

info

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

  1. ConnectrpcClient() dials the signer URL with a TLS config: optional client cert/key for mTLS (ClientCert/ClientPrivateKey), optional RootCA (lets you use self-signed certs), and InsecureSkipVerify.
  2. SignexternalSigner() returns a signer callback that:
  • Converts the transaction to apitypes.SendTxArgs via TxToSignTxArgs
    • 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:

Fieldkoanf keyPurpose
URLurlRPC endpoint of the signer. Setting this enables external signing (overrides local key).
AddressaddressHex Ethereum address the signer controls; used to verify returned signatures.
MethodmethodRPC method name, e.g., eth_signTransaction.
RootCAroot-ca(Optional) CA cert to trust — enables self-signed server certs.
ClientCertclient-cert(Optional) client cert for mTLS.
ClientPrivateKeyclient-private-key(Optional) client key for mTLS (required if client-cert set).
InsecureSkipVerifyinsecure-skip-verifySkip 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 standard eth_signTransaction shape, 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 an rpc.Server, registers a signing method, serves over HTTPS with tls.RequireAndVerifyClientCert, and prints the exact flags to pass to Nitro. Swap the local-key txOpts.Signer for 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 with RequireAndVerifyClientCert). The RPC method (externalsignertest.go:185) takes *apitypes.SendTxArgs and returns the RLP-encoded signed tx as hexutil.Bytes.