π A production-ready Go implementation of Web3 signer with MPC-KMS signing support
web3signer-go is a lightweight, secure signing service inspired by Consensys/web3signer, specifically focusing on MPC-KMS (Multi-Party Computation Key Management Service) signing.
It provides a transparent HTTP JSON-RPC proxy that:
- β Signs transactions using secure MPC-KMS (key never exposed)
- β Forwards all other requests to downstream Ethereum nodes
- β Standard Ethereum JSON-RPC - drop-in replacement for direct node access
| Feature | web3signer-go | Original web3signer |
|---|---|---|
| Signing Methods | MPC-KMS only | File, Vault, AWS KMS, YubiHSM, etc. |
| Architecture | Simple, focused | Complex, extensible |
| Language | Go | Java |
| Deployment | Single binary, minimal deps | JVM, heavier footprint |
| Use Case | Production MPC-KMS deployments | Multi-backend signing scenarios |
- β MPC-KMS Integration - Secure multi-party computation key management
- β JSON-RPC Server - HTTP server with JSON-RPC 2.0 support
- β
Transaction Signing - Supports
eth_sign,eth_signTransaction,eth_sendTransaction - β Smart Contract Support - EIP-1559 and legacy transaction types
- β Downstream Forwarding - Transparent proxy to Ethereum nodes
- β
Health Checks -
/healthand/readyendpoints for monitoring - β CORS Support - Configurable CORS headers for web applications
- β Configuration Management - CLI flags, config files, and environment variables
- β Structured Logging - Logrus-based logging with configurable levels
- β Comprehensive Testing - Unit tests and integration tests with high coverage
- β Docker Support - Multi-stage Dockerfile for production deployments
- β CI/CD Pipeline - Automated testing, linting, and security scanning
- β TLS Support - HTTPS/TLS for secure communication
- β Authentication - JWT Bearer token and API-Key authentication
- β Security Hardening - Constant-time comparisons, input validation, rate limiting
- Go 1.25 or later
- MPC-KMS service endpoint
- Downstream JSON-RPC service (e.g., Ethereum node)
# Clone the repository
git clone https://github.com/mowind/web3signer-go.git
cd web3signer-go
# Build the binary
make build
# Or install directly
go install ./cmd/web3signer/# Build the Docker image
docker build -t web3signer:latest .
# Run the container
docker run -d \
--name web3signer \
-p 9000:9000 \
-e WEB3SIGNER_HTTP_HOST=0.0.0.0 \
-e WEB3SIGNER_HTTP_PORT=9000 \
-e WEB3SIGNER_KMS_ENDPOINT=http://kms.example.com:8080 \
-e WEB3SIGNER_KMS_ACCESS_KEY_ID=YOUR_ACCESS_KEY \
-e WEB3SIGNER_KMS_SECRET_KEY=YOUR_SECRET_KEY \
-e WEB3SIGNER_KMS_KEY_ID=YOUR_KEY_ID \
-e WEB3SIGNER_DOWNSTREAM_HTTP_HOST=http://localhost \
-e WEB3SIGNER_DOWNSTREAM_HTTP_PORT=8545 \
web3signer:latestFor detailed deployment instructions, see DEPLOYMENT.md.
# Run with command-line flags
./build/web3signer \
--http-host localhost \
--http-port 9000 \
--kms-endpoint http://kms.example.com:8080 \
--kms-access-key-id YOUR_ACCESS_KEY \
--kms-secret-key YOUR_SECRET_KEY \
--kms-key-id YOUR_KEY_ID \
--downstream-http-host http://localhost \
--downstream-http-port 8545 \
--downstream-http-path / \
--log-level infoCreate a configuration file ~/.web3signer.yaml:
http:
host: localhost
port: 9000
max-request-size-mb: 10
# allowed-origins: "https://example.com,https://api.example.com" # Default: http://localhost:*,http://127.0.0.1:*
tls-enabled: false
# tls-cert-file: /path/to/cert.pem
# tls-key-file: /path/to/key.pem
auth:
enabled: true
secret: your_shared_secret_here
kms:
endpoint: http://kms.example.com:8080
access-key-id: YOUR_ACCESS_KEY
secret-key: YOUR_SECRET_KEY
key-id: YOUR_KEY_ID
downstream:
http-host: http://localhost
http-port: 8545
http-path: /
log:
level: info
format: jsonThen run with:
./build/web3signer --config ~/.web3signer.yamleth_sign- Sign arbitrary dataeth_signTransaction- Sign a transactioneth_sendTransaction- Sign and send a transaction
All other JSON-RPC methods are forwarded to the configured downstream service, including:
eth_getBalanceeth_getTransactionCounteth_calleth_getBlockByNumbernet_versionweb3_clientVersion- And more...
web3signer-go/
βββ cmd/ # Application entry points
β βββ web3signer/ # Main application
β βββ test-kms/ # KMS test utilities
βββ internal/ # Private application code
β βββ config/ # Configuration types and validation
β βββ kms/ # MPC-KMS HTTP client
β βββ server/ # HTTP server with Gin
β βββ router/ # JSON-RPC routing and handlers
β βββ jsonrpc/ # JSON-RPC types and utilities
β βββ downstream/ # Downstream service HTTP client
β βββ signer/ # Signing logic (implements ethgo.Key)
β βββ errors/ # Error types and handling
βββ test/ # Integration tests and mocks
βββ scripts/ # Build and deployment scripts
βββ .github/ # GitHub workflows and CI/CD
βββ Dockerfile # Multi-stage Docker build
βββ Makefile # Build and test commands
βββ DEPLOYMENT.md # Detailed deployment guide
βββ CLAUDE.md # AI-assisted development context
βββ README.md # This file
- Go 1.25 or later
- Docker (optional, for containerized deployment)
- golangci-lint (install with
make install-tools)
# Build all binaries
make build
# Build specific binary
go build -o web3signer ./cmd/web3signer
# Clean build artifacts
make clean
# Check development environment
make env# Run all tests
make test
# Run tests with coverage
make test-coverage
# Generate HTML coverage report
make coverage
# Run integration tests
make integration-test
# Run tests for specific package
go test ./internal/kms/...
# Run tests with verbose output
go test -v ./...
# Run tests with race detector
go test -race ./...# Format code
make fmt
# Run vet
make vet
# Run linter
make lint
# Tidy dependencies
make tidy
# Run all checks (test + lint)
make check
# Install development tools
make install-toolsThe project includes a test KMS client for development:
# Build the test-kms tool
make build
# Test a signing operation
./build/test-kms \
--endpoint http://localhost:8080 \
--access-key-id YOUR_ACCESS_KEY \
--secret-key YOUR_SECRET_KEY \
--key-id YOUR_KEY_ID--http-host- Server host (default:localhost)--http-port- Server port (default:9000)--http-max-request-size- Maximum request body size in MB (default:10)--http-allowed-origins- CORS allowed origins (default:http://localhost:*,http://127.0.0.1:*; use*to allow all origins)--tls-enabled- Enable TLS/HTTPS (default:false)--tls-cert-file- Path to TLS certificate file (required if TLS enabled)--tls-key-file- Path to TLS private key file (required if TLS enabled)--tls-auto-redirect- Auto redirect HTTP to HTTPS (default:false)
--auth-enabled- Enable authentication middleware (default:false)--auth-secret- Shared secret for Bearer tokens and API-Keys (required if auth enabled)
--kms-endpoint- MPC-KMS endpoint URL (required)--kms-access-key-id- Access key ID (required)--kms-secret-key- Secret key (required)--kms-key-id- Key ID for signing (required)--kms-address- Ethereum address associated with the key (required)
--downstream-http-host- Downstream service host (default:http://localhost)--downstream-http-port- Downstream service port (default:8545)--downstream-http-path- Downstream service path (default:/)
--log-level- Log level: debug, info, warn, error, fatal (default:info)
All configuration options can be set via environment variables using the WEB3SIGNER_ prefix:
export WEB3SIGNER_HTTP_HOST=0.0.0.0
export WEB3SIGNER_HTTP_PORT=9000
export WEB3SIGNER_HTTP_MAX_REQUEST_SIZE_MB=10
export WEB3SIGNER_HTTP_ALLOWED_ORIGINS="https://example.com,https://api.example.com"
export WEB3SIGNER_TLS_ENABLED=false
export WEB3SIGNER_AUTH_ENABLED=true
export WEB3SIGNER_AUTH_SECRET=your_shared_secret
export WEB3SIGNER_KMS_ENDPOINT=http://kms.example.com:8080
export WEB3SIGNER_KMS_ACCESS_KEY_ID=your_access_key
export WEB3SIGNER_KMS_SECRET_KEY=your_secret_key
export WEB3SIGNER_KMS_KEY_ID=your_key_id| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Service health check |
/ready |
GET | Service readiness check |
Note: These endpoints bypass authentication (if enabled) for monitoring purposes.
Response Example:
{
"status": "healthy",
"time": "2026-01-20T08:00:00Z"
}| Endpoint | Method | Description |
|---|---|---|
/ |
POST | JSON-RPC 2.0 endpoint |
When authentication is enabled (--auth-enabled=true), requests must include one of the following:
Option 1: Bearer Token
curl -X POST https://localhost:9000/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_shared_secret" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_accounts"}'Option 2: API-Key Header
curl -X POST https://localhost:9000/ \
-H "Content-Type: application/json" \
-H "X-API-Key: your_shared_secret" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_accounts"}'Security Notes:
- Both methods use the same shared secret configured via
--auth-secret - Constant-time comparison prevents timing attacks
- Generic error messages prevent information leakage
- Whitelisted paths (
/health,/ready) bypass authentication
| Method | Description |
|---|---|
eth_sign |
Sign arbitrary data with the configured key |
eth_signTransaction |
Sign a transaction (returns signed transaction) |
eth_sendTransaction |
Sign and send a transaction to the network |
eth_accounts |
Returns the configured Ethereum address |
curl -X POST http://localhost:9000/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_signTransaction",
"params": [{
"from": "0xYourAddress",
"to": "0xRecipientAddress",
"gas": "0x5208",
"gasPrice": "0x4a817c800",
"nonce": "0x0",
"value": "0xde0b6b3a7640000",
"chainId": "0x1"
}]
}'curl -X POST http://localhost:9000/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "eth_sendTransaction",
"params": [{
"from": "0xYourAddress",
"to": "0xRecipientAddress",
"gas": "0x5208",
"maxFeePerGas": "0x4a817c800",
"maxPriorityFeePerGas": "0x4a817c800",
"nonce": "0x1",
"value": "0xde0b6b3a7640000",
"chainId": "0x1"
}]
}'We welcome contributions! Please see our development guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all checks pass (
make check) - Commit with Conventional Commits
- Push and create a pull request
# 1. Fork and clone
git clone https://github.com/YOUR_USERNAME/web3signer-go.git
cd web3signer-go
# 2. Create feature branch
git checkout -b feat/amazing-feature
# 3. Make changes and test
make test
make lint
# 4. Commit your changes
git add .
git commit -m "feat(module): add amazing feature"
# 5. Push and create PR
git push origin feat/amazing-feature- Follow standard Go conventions and Effective Go
- Run
make fmtbefore committing - Ensure
make lintpasses without errors - Maintain test coverage for all changes
- Write clear, self-documenting code
We follow Conventional Commits:
feat(kms): add support for multiple key IDs
fix(signer): correct EIP-1559 transaction calculation
docs(readme): update deployment instructions
test(router): add integration test for batch requests
ci(docker): optimize multi-stage build
- Multi-key support (currently single key-id)
- Asynchronous signing approval workflow (MPC-KMS task polling)
- Prometheus metrics endpoint
- Kubernetes deployment manifests
- Performance benchmarking
- Webhook notifications for signing events
- Enhanced logging and tracing support
- Rate limiting and request throttling
- π CLAUDE.md - AI-assisted development context and architecture guide
- π¦ DEPLOYMENT.md - Detailed deployment guide with Docker and production configurations
- π§ API Documentation - JSON-RPC endpoints and examples
- π Bug Reports: GitHub Issues
- π‘ Feature Requests: GitHub Discussions
- π§ Security Issues: Please report security vulnerabilities privately via GitHub's security advisory features
This project is licensed under the GNU General Public License v3.0 (GPLv3). See the LICENSE file for details.
- Inspired by Consensys/web3signer
- Built with Gin for HTTP routing
- Uses ethgo for Ethereum utilities
- Configuration via Cobra and Viper
- Logging with Logrus
Made with β€οΈ by the web3signer-go team