Skip to content

Commit a417258

Browse files
jclapisltitanb
andauthored
feat(signer): add IP / Port Settings to Signer (#305)
Co-authored-by: ltitanb <[email protected]>
1 parent 835202f commit a417258

File tree

10 files changed

+104
-29
lines changed

10 files changed

+104
-29
lines changed

config.example.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ url = "http://0xa119589bb33ef52acbb8116832bec2b58fca590fe5c85eac5d3230b44d5bc09f
148148
# Docker image to use for the Signer module.
149149
# OPTIONAL, DEFAULT: ghcr.io/commit-boost/signer:latest
150150
# docker_image = "ghcr.io/commit-boost/signer:latest"
151+
# Host to bind the Signer API server to
152+
# OPTIONAL, DEFAULT: 127.0.0.1
153+
host = "127.0.0.1"
154+
# Port to listen for Signer API calls on
155+
# OPTIONAL, DEFAULT: 20000
156+
port = 20000
157+
151158
# For Remote signer:
152159
# [signer.remote]
153160
# URL of the Web3Signer instance

crates/cli/src/docker_init.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ use cb_common::{
1414
PBS_MODULE_NAME, PROXY_DIR_DEFAULT, PROXY_DIR_ENV, PROXY_DIR_KEYS_DEFAULT,
1515
PROXY_DIR_KEYS_ENV, PROXY_DIR_SECRETS_DEFAULT, PROXY_DIR_SECRETS_ENV, SIGNER_DEFAULT,
1616
SIGNER_DIR_KEYS_DEFAULT, SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS_DEFAULT,
17-
SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS_ENV, SIGNER_MODULE_NAME, SIGNER_PORT_ENV,
17+
SIGNER_DIR_SECRETS_ENV, SIGNER_ENDPOINT_ENV, SIGNER_KEYS_ENV, SIGNER_MODULE_NAME,
1818
SIGNER_URL_ENV,
1919
},
2020
pbs::{BUILDER_API_PATH, GET_STATUS_PATH},
21-
signer::{ProxyStore, SignerLoader},
21+
signer::{ProxyStore, SignerLoader, DEFAULT_SIGNER_PORT},
2222
types::ModuleId,
2323
utils::random_jwt_secret,
2424
};
@@ -73,7 +73,7 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
7373
let mut targets = Vec::new();
7474

7575
// address for signer API communication
76-
let signer_port = 20000;
76+
let signer_port = cb_config.signer.as_ref().map(|s| s.port).unwrap_or(DEFAULT_SIGNER_PORT);
7777
let signer_server =
7878
if let Some(SignerConfig { inner: SignerType::Remote { url }, .. }) = &cb_config.signer {
7979
url.to_string()
@@ -333,10 +333,17 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
333333
let mut signer_envs = IndexMap::from([
334334
get_env_val(CONFIG_ENV, CONFIG_DEFAULT),
335335
get_env_same(JWTS_ENV),
336-
get_env_uval(SIGNER_PORT_ENV, signer_port as u64),
337336
]);
338337

339-
let mut ports = vec![];
338+
// Bind the signer API to 0.0.0.0
339+
let container_endpoint =
340+
SocketAddr::from((Ipv4Addr::UNSPECIFIED, signer_config.port));
341+
let (key, val) = get_env_val(SIGNER_ENDPOINT_ENV, &container_endpoint.to_string());
342+
signer_envs.insert(key, val);
343+
344+
let host_endpoint = SocketAddr::from((signer_config.host, signer_config.port));
345+
let mut ports = vec![format!("{}:{}", host_endpoint, signer_config.port)];
346+
warnings.push(format!("cb_signer has an exported port on {}", signer_config.port));
340347

341348
if let Some((key, val)) = chain_spec_env.clone() {
342349
signer_envs.insert(key, val);
@@ -458,13 +465,20 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
458465
let mut signer_envs = IndexMap::from([
459466
get_env_val(CONFIG_ENV, CONFIG_DEFAULT),
460467
get_env_same(JWTS_ENV),
461-
get_env_uval(SIGNER_PORT_ENV, signer_port as u64),
462468
get_env_val(DIRK_CERT_ENV, DIRK_CERT_DEFAULT),
463469
get_env_val(DIRK_KEY_ENV, DIRK_KEY_DEFAULT),
464470
get_env_val(DIRK_DIR_SECRETS_ENV, DIRK_DIR_SECRETS_DEFAULT),
465471
]);
466472

467-
let mut ports = vec![];
473+
// Bind the signer API to 0.0.0.0
474+
let container_endpoint =
475+
SocketAddr::from((Ipv4Addr::UNSPECIFIED, signer_config.port));
476+
let (key, val) = get_env_val(SIGNER_ENDPOINT_ENV, &container_endpoint.to_string());
477+
signer_envs.insert(key, val);
478+
479+
let host_endpoint = SocketAddr::from((signer_config.host, signer_config.port));
480+
let mut ports = vec![format!("{}:{}", host_endpoint, signer_config.port)];
481+
warnings.push(format!("cb_signer has an exported port on {}", signer_config.port));
468482

469483
if let Some((key, val)) = chain_spec_env.clone() {
470484
signer_envs.insert(key, val);

crates/common/src/config/constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const SIGNER_IMAGE_DEFAULT: &str = "ghcr.io/commit-boost/signer:latest";
3333
pub const SIGNER_MODULE_NAME: &str = "signer";
3434

3535
/// Where the signer module should open the server
36-
pub const SIGNER_PORT_ENV: &str = "CB_SIGNER_PORT";
36+
pub const SIGNER_ENDPOINT_ENV: &str = "CB_SIGNER_ENDPOINT";
3737

3838
/// Comma separated list module_id=jwt_secret
3939
pub const JWTS_ENV: &str = "CB_JWTS";

crates/common/src/config/signer.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
1-
use std::{collections::HashMap, path::PathBuf};
1+
use std::{
2+
collections::HashMap,
3+
net::{Ipv4Addr, SocketAddr},
4+
path::PathBuf,
5+
};
26

37
use eyre::{bail, OptionExt, Result};
48
use serde::{Deserialize, Serialize};
59
use tonic::transport::{Certificate, Identity};
610
use url::Url;
711

812
use super::{
9-
constants::SIGNER_IMAGE_DEFAULT, load_jwt_secrets, utils::load_env_var, CommitBoostConfig,
10-
SIGNER_PORT_ENV,
13+
load_jwt_secrets, load_optional_env_var, utils::load_env_var, CommitBoostConfig,
14+
SIGNER_ENDPOINT_ENV, SIGNER_IMAGE_DEFAULT,
1115
};
1216
use crate::{
1317
config::{DIRK_CA_CERT_ENV, DIRK_CERT_ENV, DIRK_DIR_SECRETS_ENV, DIRK_KEY_ENV},
14-
signer::{ProxyStore, SignerLoader},
18+
signer::{ProxyStore, SignerLoader, DEFAULT_SIGNER_PORT},
1519
types::{Chain, ModuleId},
20+
utils::{default_host, default_u16},
1621
};
1722

1823
#[derive(Debug, Serialize, Deserialize, Clone)]
1924
#[serde(rename_all = "snake_case")]
2025
pub struct SignerConfig {
26+
/// Host address to listen for signer API calls on
27+
#[serde(default = "default_host")]
28+
pub host: Ipv4Addr,
29+
/// Port to listen for signer API calls on
30+
#[serde(default = "default_u16::<DEFAULT_SIGNER_PORT>")]
31+
pub port: u16,
2132
/// Docker image of the module
2233
#[serde(default = "default_signer")]
2334
pub docker_image: String,
@@ -87,7 +98,7 @@ pub struct StartSignerConfig {
8798
pub chain: Chain,
8899
pub loader: Option<SignerLoader>,
89100
pub store: Option<ProxyStore>,
90-
pub server_port: u16,
101+
pub endpoint: SocketAddr,
91102
pub jwts: HashMap<ModuleId, String>,
92103
pub dirk: Option<DirkConfig>,
93104
}
@@ -97,15 +108,22 @@ impl StartSignerConfig {
97108
let config = CommitBoostConfig::from_env_path()?;
98109

99110
let jwts = load_jwt_secrets()?;
100-
let server_port = load_env_var(SIGNER_PORT_ENV)?.parse()?;
101111

102-
let signer = config.signer.ok_or_eyre("Signer config is missing")?.inner;
112+
let signer_config = config.signer.ok_or_eyre("Signer config is missing")?;
113+
114+
// Load the server endpoint first from the env var if present, otherwise the
115+
// config
116+
let endpoint = if let Some(endpoint) = load_optional_env_var(SIGNER_ENDPOINT_ENV) {
117+
endpoint.parse()?
118+
} else {
119+
SocketAddr::from((signer_config.host, signer_config.port))
120+
};
103121

104-
match signer {
122+
match signer_config.inner {
105123
SignerType::Local { loader, store, .. } => Ok(StartSignerConfig {
106124
chain: config.chain,
107125
loader: Some(loader),
108-
server_port,
126+
endpoint,
109127
jwts,
110128
store,
111129
dirk: None,
@@ -133,7 +151,7 @@ impl StartSignerConfig {
133151

134152
Ok(StartSignerConfig {
135153
chain: config.chain,
136-
server_port,
154+
endpoint,
137155
jwts,
138156
loader: None,
139157
store,

crates/common/src/signer/constants.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub const DEFAULT_SIGNER_PORT: u16 = 20000;

crates/common/src/signer/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
mod constants;
12
mod loader;
23
mod schemes;
34
mod store;
45
mod types;
56

7+
pub use constants::*;
68
pub use loader::*;
79
pub use schemes::*;
810
pub use store::*;

crates/signer/src/service.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
1+
use std::{collections::HashMap, sync::Arc};
22

33
use axum::{
44
extract::{Request, State},
@@ -67,7 +67,7 @@ impl SigningService {
6767
let loaded_consensus = state.manager.read().await.available_consensus_signers();
6868
let loaded_proxies = state.manager.read().await.available_proxy_signers();
6969

70-
info!(version = COMMIT_BOOST_VERSION, commit_hash = COMMIT_BOOST_COMMIT, modules =? module_ids, port =? config.server_port, loaded_consensus, loaded_proxies, "Starting signing service");
70+
info!(version = COMMIT_BOOST_VERSION, commit_hash = COMMIT_BOOST_COMMIT, modules =? module_ids, endpoint =? config.endpoint, loaded_consensus, loaded_proxies, "Starting signing service");
7171

7272
SigningService::init_metrics(config.chain)?;
7373

@@ -81,8 +81,7 @@ impl SigningService {
8181
.route_layer(middleware::from_fn(log_request))
8282
.route(STATUS_PATH, get(handle_status));
8383

84-
let address = SocketAddr::from(([0, 0, 0, 0], config.server_port));
85-
let listener = TcpListener::bind(address).await?;
84+
let listener = TcpListener::bind(config.endpoint).await?;
8685

8786
axum::serve(listener, app).await.wrap_err("signer server exited")
8887
}

docs/docs/get_started/building.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ url = "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1d
121121
enabled = true
122122

123123
[signer]
124+
port = 20000
125+
124126
[signer.local.loader]
125127
format = "lighthouse"
126128
keys_path = "/tmp/keys"
@@ -155,20 +157,19 @@ This will create a binary in `./target/release/commit-boost-signer`. To verify i
155157
The signer needs the following environment variables set:
156158
- `CB_CONFIG` = path of your config file.
157159
- `CB_JWTS` = a dummy key-value pair of [JWT](https://en.wikipedia.org/wiki/JSON_Web_Token) values for various services. Since we don't need them for the sake of just testing the binary, we can use something like `"test_jwts=dummy"`.
158-
- `CB_SIGNER_PORT` = the network port to listen for signer requests on. Default is `20000`.
159160

160161
Set these values, create the `keys` and `secrets` directories listed in the configuration file, and run the binary:
161162

162163
```
163164
mkdir -p /tmp/keys && mkdir -p /tmp/secrets
164-
CB_CONFIG=cb-config.toml CB_JWTS="test_jwts=dummy" CB_SIGNER_PORT=20000 ./target/release/commit-boost-signer
165+
CB_CONFIG=cb-config.toml CB_JWTS="test_jwts=dummy" ./target/release/commit-boost-signer
165166
```
166167

167168
You should see output like this:
168169
```
169-
2025-05-07T21:43:46.385535Z WARN Proxy store not configured. Proxies keys and delegations will not be persisted
170-
2025-05-07T21:43:46.393507Z INFO Starting signing service version="0.7.0" commit_hash="58082edb1213596667afe8c3950cd997ab85f4f3" modules=["test_jwts"] port=20000 loaded_consensus=0 loaded_proxies=0
171-
2025-05-07T21:43:46.393574Z WARN No metrics server configured
170+
2025-06-03T04:57:19.815702Z WARN Proxy store not configured. Proxies keys and delegations will not be persisted
171+
2025-06-03T04:57:19.818193Z INFO Starting signing service version="0.8.0-rc.1" commit_hash="3eed5268f07803c55cca7d7e2e14a7017098f797" modules=["test"] endpoint=127.0.0.1:20000 loaded_consensus=0 loaded_proxies=0
172+
2025-06-03T04:57:19.818229Z WARN No metrics server configured
172173
```
173174

174175
If you do, then the binary works.

docs/docs/get_started/configuration.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Commit-Boost supports both local and remote signers. The signer module is respon
3939
To start a local signer module, you need to include its parameters in the config file
4040

4141
```toml
42+
[pbs]
43+
...
44+
with_signer = true
45+
46+
[signer]
47+
port = 20000
48+
4249
[signer.local.loader]
4350
format = "lighthouse"
4451
keys_path = "/path/to/keys"
@@ -64,7 +71,13 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea
6471

6572
#### Config:
6673
```toml
74+
[pbs]
75+
...
76+
with_signer = true
77+
6778
[signer]
79+
port = 20000
80+
6881
[signer.local.loader]
6982
format = "lighthouse"
7083
keys_path = "keys"
@@ -87,7 +100,13 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea
87100

88101
#### Config:
89102
```toml
103+
[pbs]
104+
...
105+
with_signer = true
106+
90107
[signer]
108+
port = 20000
109+
91110
[signer.local.loader]
92111
format = "prysm"
93112
keys_path = "wallet/direct/accounts/all-accounts.keystore.json"
@@ -110,7 +129,13 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea
110129

111130
#### Config:
112131
```toml
132+
[pbs]
133+
...
134+
with_signer = true
135+
113136
[signer]
137+
port = 20000
138+
114139
[signer.local.loader]
115140
format = "teku"
116141
keys_path = "keys"
@@ -132,7 +157,13 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea
132157

133158
#### Config:
134159
```toml
160+
[pbs]
161+
...
162+
with_signer = true
163+
135164
[signer]
165+
port = 20000
166+
136167
[signer.local.loader]
137168
format = "lodestar"
138169
keys_path = "keys"
@@ -299,6 +330,8 @@ port = 18550
299330
url = ""
300331

301332
[signer]
333+
port = 20000
334+
302335
[signer.loader]
303336
format = "lighthouse"
304337
keys_path = "/path/to/keys"

docs/docs/get_started/running/binary.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ Modules need some environment variables to work correctly.
2222

2323
### PBS Module
2424
- `CB_BUILDER_URLS`: optional, comma-separated list of urls to `events` modules where to post builder events.
25-
- `CB_PBS_ENDPOINT`: optional, override the endpoint where the PBS module will open the port for the beacon node.
25+
- `CB_PBS_ENDPOINT`: optional, override to specify the `IP:port` endpoint where the PBS module will open the port for the beacon node.
2626
- `CB_MUX_PATH_{ID}`: optional, override where to load mux validator keys for mux with `id=\{ID\}`.
2727

2828
### Signer Module
29-
- `CB_SIGNER_PORT`: required, port to open the signer server on.
29+
- `CB_SIGNER_ENDPOINT`: optional, override to specify the `IP:port` endpoint to bind the signer server to.
3030
- For loading keys we currently support:
3131
- `CB_SIGNER_LOADER_FILE`: path to a `.json` with plaintext keys (for testing purposes only).
3232
- `CB_SIGNER_LOADER_FORMAT`, `CB_SIGNER_LOADER_KEYS_DIR` and `CB_SIGNER_LOADER_SECRETS_DIR`: paths to the `keys` and `secrets` directories or files (ERC-2335 style keystores, see [Signer config](../configuration/#signer-module) for more info).

0 commit comments

Comments
 (0)