Skip to content

Commit 6a8497f

Browse files
committed
Added client auth settings to the remote signer config
1 parent 7dba8d1 commit 6a8497f

File tree

7 files changed

+79
-10
lines changed

7 files changed

+79
-10
lines changed

config.example.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ jwt_auth_fail_timeout_seconds = 300
188188
# [signer.remote]
189189
# URL of the Web3Signer instance
190190
# url = "https://remote.signer.url"
191+
# Path to the client certificate for client authentication
192+
# OPTIONAL
193+
# cert_path = "/path/to/client.crt"
194+
# Path to the client key for client authentication
195+
# OPTIONAL
196+
# key_path = "/path/to/client.key"
197+
191198
# For Dirk signer:
192199
# [signer.dirk]
193200
# Path to the client certificate to authenticate with Dirk

crates/cli/src/docker_init.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
7474
// address for signer API communication
7575
let signer_port = cb_config.signer.as_ref().map(|s| s.port).unwrap_or(SIGNER_PORT_DEFAULT);
7676
let signer_server =
77-
if let Some(SignerConfig { inner: SignerType::Remote { url }, .. }) = &cb_config.signer {
77+
if let Some(SignerConfig { inner: SignerType::Remote { url, client_auth: _ }, .. }) =
78+
&cb_config.signer
79+
{
7880
url.to_string()
7981
} else {
8082
format!("http://cb_signer:{signer_port}")

crates/common/src/commit/client.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use std::time::{Duration, Instant};
22

33
use alloy::primitives::Address;
44
use eyre::WrapErr;
5-
use reqwest::header::{AUTHORIZATION, HeaderMap, HeaderValue};
5+
use reqwest::{
6+
Identity,
7+
header::{AUTHORIZATION, HeaderMap, HeaderValue},
8+
};
69
use serde::Deserialize;
710
use url::Url;
811

@@ -16,6 +19,7 @@ use super::{
1619
};
1720
use crate::{
1821
DEFAULT_REQUEST_TIMEOUT,
22+
config::ClientAuthConfig,
1923
constants::SIGNER_JWT_EXPIRATION,
2024
signer::EcdsaSignature,
2125
types::{BlsPublicKey, BlsSignature, Jwt, ModuleId},
@@ -35,7 +39,12 @@ pub struct SignerClient {
3539

3640
impl SignerClient {
3741
/// Create a new SignerClient
38-
pub fn new(signer_server_url: Url, jwt_secret: Jwt, module_id: ModuleId) -> eyre::Result<Self> {
42+
pub fn new(
43+
signer_server_url: Url,
44+
jwt_secret: Jwt,
45+
module_id: ModuleId,
46+
client_auth: Option<ClientAuthConfig>,
47+
) -> eyre::Result<Self> {
3948
let jwt = create_jwt(&module_id, &jwt_secret)?;
4049

4150
let mut auth_value =
@@ -45,10 +54,18 @@ impl SignerClient {
4554
let mut headers = HeaderMap::new();
4655
headers.insert(AUTHORIZATION, auth_value);
4756

48-
let client = reqwest::Client::builder()
49-
.timeout(DEFAULT_REQUEST_TIMEOUT)
50-
.default_headers(headers)
51-
.build()?;
57+
let mut client =
58+
reqwest::Client::builder().timeout(DEFAULT_REQUEST_TIMEOUT).default_headers(headers);
59+
60+
if let Some(ClientAuthConfig { cert_path, key_path }) = client_auth {
61+
let cert = std::fs::read_to_string(cert_path)?;
62+
let key = std::fs::read_to_string(key_path)?;
63+
let buffer = format!("{cert}\n{key}");
64+
let identity = Identity::from_pem(buffer.as_bytes())?;
65+
client = client.identity(identity);
66+
}
67+
68+
let client = client.build()?;
5269

5370
Ok(Self {
5471
url: signer_server_url,

crates/common/src/config/module.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use toml::Table;
77
use crate::{
88
commit::client::SignerClient,
99
config::{
10+
SignerConfig, SignerType,
1011
constants::{CONFIG_ENV, MODULE_ID_ENV, MODULE_JWT_ENV, SIGNER_URL_ENV},
1112
load_env_var,
1213
utils::load_file_from_env,
@@ -79,6 +80,7 @@ pub fn load_commit_module_config<T: DeserializeOwned>() -> Result<StartCommitMod
7980
struct StubConfig<U> {
8081
chain: Chain,
8182
modules: Vec<ThisModule<U>>,
83+
signer: Option<SignerConfig>,
8284
}
8385

8486
// load module config including the extra data (if any)
@@ -101,7 +103,16 @@ pub fn load_commit_module_config<T: DeserializeOwned>() -> Result<StartCommitMod
101103
.find(|m| m.static_config.id == module_id)
102104
.wrap_err(format!("failed to find module for {module_id}"))?;
103105

104-
let signer_client = SignerClient::new(signer_server_url, module_jwt, module_id)?;
106+
let client_auth = if let Some(signer) = cb_config.signer {
107+
match signer.inner {
108+
SignerType::Remote { url: _, client_auth } => client_auth,
109+
_ => None,
110+
}
111+
} else {
112+
None
113+
};
114+
115+
let signer_client = SignerClient::new(signer_server_url, module_jwt, module_id, client_auth)?;
105116

106117
Ok(StartCommitModuleConfig {
107118
id: module_config.static_config.id,

crates/common/src/config/pbs.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
commit::client::SignerClient,
2323
config::{
2424
CONFIG_ENV, MODULE_JWT_ENV, MuxKeysLoader, PBS_MODULE_NAME, PbsMuxes, SIGNER_URL_ENV,
25-
load_env_var, load_file_from_env,
25+
SignerConfig, SignerType, load_env_var, load_file_from_env,
2626
},
2727
pbs::{
2828
DEFAULT_PBS_PORT, DEFAULT_REGISTRY_REFRESH_SECONDS, DefaultTimeout, LATE_IN_SLOT_TIME_MS,
@@ -323,6 +323,7 @@ pub async fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<(PbsModuleC
323323
relays: Vec<RelayConfig>,
324324
pbs: CustomPbsConfig<U>,
325325
muxes: Option<PbsMuxes>,
326+
signer: Option<SignerConfig>,
326327
}
327328

328329
// load module config including the extra data (if any)
@@ -375,13 +376,22 @@ pub async fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<(PbsModuleC
375376
let all_relays = all_relays.into_values().collect();
376377

377378
let signer_client = if cb_config.pbs.static_config.with_signer {
378-
// if custom pbs requires a signer client, load jwt
379+
// if custom pbs requires a signer client, load jwt and client auth info
379380
let module_jwt = Jwt(load_env_var(MODULE_JWT_ENV)?);
380381
let signer_server_url = load_env_var(SIGNER_URL_ENV)?.parse()?;
382+
let client_auth = if let Some(signer) = cb_config.signer {
383+
match signer.inner {
384+
SignerType::Remote { url: _, client_auth } => client_auth,
385+
_ => None,
386+
}
387+
} else {
388+
None
389+
};
381390
Some(SignerClient::new(
382391
signer_server_url,
383392
module_jwt,
384393
ModuleId(PBS_MODULE_NAME.to_string()),
394+
client_auth,
385395
)?)
386396
} else {
387397
None

crates/common/src/config/signer.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ pub struct DirkHostConfig {
8383
pub wallets: Vec<String>,
8484
}
8585

86+
/// Client authentication configuration for remote signers
87+
#[derive(Debug, Serialize, Deserialize, Clone)]
88+
#[serde(rename_all = "snake_case")]
89+
pub struct ClientAuthConfig {
90+
/// Path to the client certificate
91+
pub cert_path: PathBuf,
92+
/// Path to the client key
93+
pub key_path: PathBuf,
94+
}
95+
8696
#[derive(Debug, Serialize, Deserialize, Clone)]
8797
#[serde(rename_all = "snake_case")]
8898
pub enum SignerType {
@@ -97,6 +107,9 @@ pub enum SignerType {
97107
Remote {
98108
/// Complete URL of the base API endpoint
99109
url: Url,
110+
/// Client authentication configuration
111+
#[serde(flatten)]
112+
client_auth: Option<ClientAuthConfig>,
100113
},
101114
/// Dirk remote signer module
102115
Dirk {

docs/docs/get_started/configuration.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,15 @@ Web3Signer implements the same API as Commit-Boost, so there's no need to set up
318318
url = "https://remote.signer.url"
319319
```
320320

321+
Optionally, you can also provide a client certificate and corresponding private key if the remote signer requires client authentication:
322+
323+
```toml
324+
[signer.remote]
325+
url = "https://remote.signer.url"
326+
cert_path = "/path/to/client.crt"
327+
key_path = "/path/to/client.key"
328+
```
329+
321330
#### Dirk
322331

323332
Dirk is a distributed key management system that can be used to sign transactions. In this case the Signer module is needed as an intermediary between the modules and Dirk. The following parameters are needed:

0 commit comments

Comments
 (0)