mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
when the HTTPS server fails, handle that gracefully (#2546)
This commit is contained in:
parent
816fde766f
commit
48f33fb8c9
|
@ -9,6 +9,7 @@ set -e
|
|||
|
||||
WAIT_TIMER=5
|
||||
|
||||
|
||||
echo "Building release binaries..."
|
||||
cargo build --release --bin kanidm --bin kanidmd
|
||||
|
||||
|
@ -18,6 +19,7 @@ if [ -d '.git' ]; then
|
|||
cd server/daemon/ || exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f "run_insecure_dev_server.sh" ]; then
|
||||
echo "I'm not sure where you are, please run this from the root of the repository or the server/daemon directory"
|
||||
exit 1
|
||||
|
@ -29,12 +31,13 @@ echo "Generating certificates..."
|
|||
cargo run --bin kanidmd --release cert-generate --config ../../examples/insecure_server.toml
|
||||
|
||||
echo "Making sure it runs with the DB..."
|
||||
cargo run --bin kanidmd --release recover-account idm_admin -o json
|
||||
cargo run --bin kanidmd --release recover-account idm_admin -o json --config ../../examples/insecure_server.toml
|
||||
|
||||
echo "Running the server..."
|
||||
cargo run --bin kanidmd --release server --config ../../examples/insecure_server.toml &
|
||||
KANIDMD_PID=$!
|
||||
echo "${KANIDMD_PID}"
|
||||
echo "Kanidm PID: ${KANIDMD_PID}"
|
||||
|
||||
|
||||
if [ "$(jobs -p | wc -l)" -eq 0 ]; then
|
||||
echo "Kanidmd failed to start!"
|
||||
|
@ -48,8 +51,8 @@ KANIDM_URL="$(rg origin "${KANIDM_CONFIG_FILE}" | awk '{print $NF}' | tr -d '"')
|
|||
KANIDM_CA_PATH="/tmp/kanidm/ca.pem"
|
||||
|
||||
while true; do
|
||||
echo "Waiting the server to start... testing ${KANIDM_URL}"
|
||||
curl --cacert "${KANIDM_CA_PATH}" -fs "${KANIDM_URL}" >/dev/null && break
|
||||
echo "Waiting for the server to start... testing ${KANIDM_URL}"
|
||||
curl --cacert "${KANIDM_CA_PATH}" -fs "${KANIDM_URL}/status" >/dev/null && break
|
||||
sleep 2
|
||||
ATTEMPT="$((ATTEMPT + 1))"
|
||||
if [ "${ATTEMPT}" -gt 3 ]; then
|
||||
|
|
|
@ -181,6 +181,7 @@ pub async fn create_https_server(
|
|||
qe_w_ref: &'static QueryServerWriteV1,
|
||||
qe_r_ref: &'static QueryServerReadV1,
|
||||
mut rx: broadcast::Receiver<CoreAction>,
|
||||
server_message_tx: broadcast::Sender<CoreAction>,
|
||||
) -> Result<tokio::task::JoinHandle<()>, ()> {
|
||||
let js_files = get_js_files(config.role)?;
|
||||
// set up the CSP headers
|
||||
|
@ -354,10 +355,26 @@ pub async fn create_https_server(
|
|||
tokio::spawn(axum_server::bind(addr).serve(app))
|
||||
}
|
||||
} => {
|
||||
if let Err(err) = res {
|
||||
error!("Web server exited with {:?}", err);
|
||||
}
|
||||
match res {
|
||||
Ok(res_inner) => {
|
||||
match res_inner {
|
||||
Ok(_) => debug!("Web server exited OK"),
|
||||
Err(err) => {
|
||||
error!("Web server exited with {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
Err(err) => {
|
||||
error!("Web server exited with {:?}", err);
|
||||
}
|
||||
};
|
||||
if let Err(err) = server_message_tx.send(CoreAction::Shutdown) {
|
||||
error!("Web server failed to send shutdown message! {:?}", err)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
opentelemetry::global::shutdown_tracer_provider();
|
||||
|
@ -399,10 +416,7 @@ async fn server_loop(
|
|||
|
||||
// If configured, setup TLS client authentication.
|
||||
if let Some(client_ca) = tls_param.client_ca.as_ref() {
|
||||
debug!(
|
||||
"Configuring client certificates from {}",
|
||||
client_ca.display()
|
||||
);
|
||||
info!("Loading client certificates from {}", client_ca.display());
|
||||
|
||||
let verify = SslVerifyMode::PEER;
|
||||
// In future we may add a "require mTLS option" which would necesitate this.
|
||||
|
@ -425,7 +439,11 @@ async fn server_loop(
|
|||
let read_dir = fs::read_dir(client_ca).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
format!(
|
||||
"Failed to create TLS listener while loading client ca from {}: {:?}",
|
||||
client_ca.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
||||
|
@ -458,7 +476,10 @@ async fn server_loop(
|
|||
cert_store.add_cert(cert.clone()).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
format!(
|
||||
"Failed to load cert store while creating TLS listener: {:?}",
|
||||
err
|
||||
),
|
||||
)
|
||||
})?;
|
||||
// This tells the client what CA's they should use. It DOES NOT
|
||||
|
|
|
@ -748,7 +748,7 @@ impl Display for TaskName {
|
|||
|
||||
pub struct CoreHandle {
|
||||
clean_shutdown: bool,
|
||||
tx: broadcast::Sender<CoreAction>,
|
||||
pub tx: broadcast::Sender<CoreAction>,
|
||||
/// This stores a name for the handle, and the handle itself so we can tell which failed/succeeded at the end.
|
||||
handles: Vec<(TaskName, tokio::task::JoinHandle<()>)>,
|
||||
}
|
||||
|
@ -1068,6 +1068,7 @@ pub async fn create_server_core(
|
|||
server_write_ref,
|
||||
server_read_ref,
|
||||
broadcast_tx.subscribe(),
|
||||
broadcast_tx.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
|
|
@ -530,6 +530,43 @@ async fn kanidm_main() -> ExitCode {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(ca_dir) = &(sconfig.tls_client_ca) {
|
||||
// check that the TLS client CA config option is what we expect
|
||||
let ca_dir_path = PathBuf::from(&ca_dir);
|
||||
if !ca_dir_path.exists() {
|
||||
error!(
|
||||
"TLS CA folder {} does not exist, server startup will FAIL!",
|
||||
ca_dir
|
||||
);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(&ca_dir_path);
|
||||
info!(%diag);
|
||||
}
|
||||
|
||||
let i_meta = match metadata(&ca_dir_path) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
error!("Unable to read metadata for '{}' - {:?}", ca_dir, e);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(&ca_dir_path);
|
||||
info!(%diag);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
if !i_meta.is_dir() {
|
||||
error!(
|
||||
"ERROR: Refusing to run - TLS Client CA folder {} may not be a directory",
|
||||
ca_dir
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
if kanidm_lib_file_permissions::readonly(&i_meta) {
|
||||
warn!("WARNING: TLS Client CA folder permissions on {} indicate it may not be RW. This could cause the server start up to fail!", ca_dir);
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if i_meta.mode() & 0o007 != 0 {
|
||||
warn!("WARNING: TLS Client CA folder {} has 'everyone' permission bits in the mode. This could be a security risk ...", ca_dir);
|
||||
}
|
||||
}
|
||||
|
||||
let sctx = create_server_core(config, config_test).await;
|
||||
if !config_test {
|
||||
// On linux, notify systemd.
|
||||
|
@ -541,46 +578,54 @@ async fn kanidm_main() -> ExitCode {
|
|||
loop {
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
let mut listener = sctx.tx.subscribe();
|
||||
tokio::select! {
|
||||
Ok(()) = tokio::signal::ctrl_c() => {
|
||||
break
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::terminate();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
break
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::alarm();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::hangup();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::user_defined1();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::user_defined2();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
Ok(()) = tokio::signal::ctrl_c() => {
|
||||
break
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::terminate();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
break
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::alarm();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::hangup();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::user_defined1();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
Some(()) = async move {
|
||||
let sigterm = tokio::signal::unix::SignalKind::user_defined2();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
tokio::signal::unix::signal(sigterm).unwrap().recv().await
|
||||
} => {
|
||||
// Ignore
|
||||
}
|
||||
// we got a message on thr broadcast from somewhere else
|
||||
Ok(msg) = async move {
|
||||
listener.recv().await
|
||||
} => {
|
||||
debug!("Main loop received message: {:?}", msg);
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_family = "windows")]
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue