TLS guardrails (insecure http refusal, custom CAs) and deployment guide
This commit is contained in:
+55
-3
@@ -31,6 +31,8 @@ pub struct RelayOptions {
|
||||
pub url: Option<String>,
|
||||
pub registry: Option<String>,
|
||||
pub ma_key: Option<String>,
|
||||
pub ca_cert: Option<String>,
|
||||
pub allow_insecure: bool,
|
||||
pub max_hops: usize,
|
||||
}
|
||||
|
||||
@@ -42,6 +44,8 @@ impl Default for RelayOptions {
|
||||
url: None,
|
||||
registry: None,
|
||||
ma_key: None,
|
||||
ca_cert: None,
|
||||
allow_insecure: false,
|
||||
max_hops: 3,
|
||||
}
|
||||
}
|
||||
@@ -84,6 +88,23 @@ impl Relay {
|
||||
if !options.peers.is_empty() && options.url.is_none() {
|
||||
return Err(anyhow!("--url is required when --peer is set"));
|
||||
}
|
||||
if !options.allow_insecure {
|
||||
let mut urls = options.peers.clone();
|
||||
if let Some(registry) = &options.registry {
|
||||
urls.push(registry.clone());
|
||||
}
|
||||
let insecure = crate::net::insecure_http_urls(urls);
|
||||
if !insecure.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"refusing plain http endpoints (use https, configure --ca-cert, or set --allow-insecure for private networks): {}",
|
||||
insecure.join(", ")
|
||||
));
|
||||
}
|
||||
}
|
||||
let client = crate::net::build_client(
|
||||
options.ca_cert.as_deref().map(std::path::Path::new),
|
||||
Duration::from_secs(5),
|
||||
)?;
|
||||
let relay = Arc::new(Self {
|
||||
inner: Mutex::new(Inner {
|
||||
members: HashMap::new(),
|
||||
@@ -93,9 +114,7 @@ impl Relay {
|
||||
}),
|
||||
options,
|
||||
registry,
|
||||
client: reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(5))
|
||||
.build()?,
|
||||
client,
|
||||
notify: Notify::new(),
|
||||
});
|
||||
if let Some(watcher) = &relay.registry {
|
||||
@@ -520,3 +539,36 @@ fn backpressure(status: StatusCode, missed: u64) -> Response {
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn refuses_plain_http_peers_off_loopback() {
|
||||
let options = RelayOptions {
|
||||
peers: vec!["http://10.0.0.1:7700".to_string()],
|
||||
url: Some("http://10.0.0.1:7700".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
assert!(Relay::new(options).is_err());
|
||||
|
||||
let options = RelayOptions {
|
||||
peers: vec!["http://10.0.0.1:7700".to_string()],
|
||||
url: Some("http://10.0.0.1:7700".to_string()),
|
||||
allow_insecure: true,
|
||||
..Default::default()
|
||||
};
|
||||
assert!(Relay::new(options).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loopback_peers_need_no_opt_in() {
|
||||
let options = RelayOptions {
|
||||
peers: vec!["http://127.0.0.1:7701".to_string()],
|
||||
url: Some("http://127.0.0.1:7700".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
assert!(Relay::new(options).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user