diff --git a/nexus/src/lib.rs b/nexus/src/lib.rs index 2c6df32bbc..0ada48e203 100644 --- a/nexus/src/lib.rs +++ b/nexus/src/lib.rs @@ -173,7 +173,7 @@ impl Server { tls_config.map(dropshot::ConfigTls::Dynamic), ) .map_err(|error| { - format!("initializing external server: {}", error) + format!("initializing external techport server: {}", error) })?; server_starter_external_techport.start() }; diff --git a/smf/wicketd/manifest.xml b/smf/wicketd/manifest.xml index e15c20d013..778a7abf2d 100644 --- a/smf/wicketd/manifest.xml +++ b/smf/wicketd/manifest.xml @@ -25,7 +25,11 @@ for TLS both of which are fine for our standard wicketd deployment, which only - listens on a `::1` (IPv6 localhost) address without TLS. + listens on a `::1` (IPv6 localhost) address without TLS. If any of the + above assumptions are violated, the `reload-config` endpoint we hit + here will return an error (either directly, if we attempt to change + `config/address`, or indirectly because we tried to post via http but + it expected https). --> Result<(), CmdError> { Some(addr) => Some(Ipv6Subnet::new(addr)), None if read_smf_config => { let smf_values = SmfConfigValues::read_current() - .map_err(|e| CmdError::Failure(e.to_string()))? - .ok_or_else(|| { - CmdError::Failure( - "--read-smf-config only available on illumos" - .to_string(), - ) - })?; + .map_err(|e| CmdError::Failure(e.to_string()))?; smf_values.rack_subnet } None => None, diff --git a/wicketd/src/context.rs b/wicketd/src/context.rs index d59422f9c6..eeecc3fa64 100644 --- a/wicketd/src/context.rs +++ b/wicketd/src/context.rs @@ -24,6 +24,7 @@ use std::sync::OnceLock; /// Shared state used by API handlers pub struct ServerContext { + pub(crate) bind_address: SocketAddrV6, pub mgs_handle: MgsHandle, pub mgs_client: gateway_client::Client, pub(crate) log: slog::Logger, diff --git a/wicketd/src/http_entrypoints.rs b/wicketd/src/http_entrypoints.rs index 5b424fb3bb..be0f681601 100644 --- a/wicketd/src/http_entrypoints.rs +++ b/wicketd/src/http_entrypoints.rs @@ -1259,14 +1259,16 @@ async fn post_reload_config( ) })?; - let Some(smf_values) = smf_values else { + let rqctx = rqctx.context(); + + // We do not allow a config reload to change our bound address; return an + // error if the caller is attempting to do so. + if rqctx.bind_address != smf_values.address { return Err(HttpError::for_bad_request( None, - "reloading config from SMF only available on illumos".to_string(), + "listening address cannot be reconfigured".to_string(), )); - }; - - let rqctx = rqctx.context(); + } if let Some(rack_subnet) = smf_values.rack_subnet { let resolver = Resolver::new_from_subnet( diff --git a/wicketd/src/lib.rs b/wicketd/src/lib.rs index b4c1e5e3ca..fa42cfaea6 100644 --- a/wicketd/src/lib.rs +++ b/wicketd/src/lib.rs @@ -16,7 +16,7 @@ mod preflight_check; mod rss_config; mod update_tracker; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use artifacts::{WicketdArtifactServer, WicketdArtifactStore}; use bootstrap_addrs::BootstrapPeers; pub use config::Config; @@ -63,17 +63,19 @@ pub struct Args { } pub struct SmfConfigValues { + pub address: SocketAddrV6, pub rack_subnet: Option>, } impl SmfConfigValues { #[cfg(target_os = "illumos")] - pub fn read_current() -> Result> { + pub fn read_current() -> Result { use anyhow::Context; use illumos_utils::scf::ScfHandle; const CONFIG_PG: &str = "config"; const PROP_RACK_SUBNET: &str = "rack-subnet"; + const PROP_ADDRESS: &str = "address"; let scf = ScfHandle::new()?; let instance = scf.self_instance()?; @@ -94,12 +96,22 @@ impl SmfConfigValues { Some(Ipv6Subnet::new(addr)) }; - Ok(Some(Self { rack_subnet })) + let address = { + let address = config.value_as_string(PROP_ADDRESS)?; + address.parse().with_context(|| { + format!( + "failed to parse {CONFIG_PG}/{PROP_ADDRESS} \ + value {address:?} as a socket address" + ) + })? + }; + + Ok(Some(Self { address, rack_subnet })) } #[cfg(not(target_os = "illumos"))] - pub fn read_current() -> Result> { - Ok(None) + pub fn read_current() -> Result { + bail!("reading SMF config only available on illumos") } } @@ -182,6 +194,7 @@ impl Server { &dropshot_config, http_entrypoints::api(), ServerContext { + bind_address: args.address, mgs_handle, mgs_client, log: log.clone(),