mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 04:27:02 +01:00
Changing to allow startup without a config file (#2582)
* Changing to allow startup without a config file, using environment variables
This commit is contained in:
parent
7b490d73dc
commit
4096b8f02d
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1121,6 +1121,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sketching",
|
||||
"tempfile",
|
||||
"tikv-jemallocator",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
|
1
Makefile
1
Makefile
|
@ -186,6 +186,7 @@ doc/format: ## Format docs and the Kanidm book
|
|||
-not -path './target/*' \
|
||||
-not -path './docs/*' \
|
||||
-not -path '*/.venv/*' -not -path './vendor/*'\
|
||||
-not -path '*/.*/*' \
|
||||
-name \*.md \
|
||||
-exec deno fmt --check $(MARKDOWN_FORMAT_ARGS) "{}" +
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ The maximum length in seconds that an authentication session may exist for.
|
|||
The minimum security strength of credentials that may be assigned to this account. In order from
|
||||
weakest to strongest:
|
||||
|
||||
* `any`
|
||||
* `mfa`
|
||||
* `passkey`
|
||||
* `attested_passkey`
|
||||
- `any`
|
||||
- `mfa`
|
||||
- `passkey`
|
||||
- `attested_passkey`
|
||||
|
||||
### Password Minimum Length
|
||||
|
||||
|
|
|
@ -4,12 +4,29 @@ In this section we will configure your server and create its container instance.
|
|||
|
||||
## Configuring server.toml
|
||||
|
||||
You need a configuration file in the volume named `server.toml`. (Within the container it should be
|
||||
`/data/server.toml`) The following is a commented example configuration.
|
||||
There are two methods for configuration:
|
||||
|
||||
The full options and explanations are in the
|
||||
1. Providing a configuration file in the volume named `server.toml`. (Within the container it should
|
||||
be `/data/server.toml`)
|
||||
2. Using environment variables to specify configuration options (uppercased, prefixed with
|
||||
`KANIDM_`).
|
||||
|
||||
You can use one or both methods, but environment variables take precedence over options specified in
|
||||
files.The full options and explanations are in the
|
||||
[kanidmd_core::config::ServerConfig](https://kanidm.github.io/kanidm/master/rustdoc/kanidmd_core/config/struct.ServerConfig.html)
|
||||
for your particular build.
|
||||
docs page for your particular build.
|
||||
|
||||
<!-- deno-fmt-ignore-start -->
|
||||
|
||||
{{#template templates/kani-warning.md
|
||||
imagepath=images
|
||||
title=Warning!
|
||||
text=You MUST set the "domain", "origin", "tls_chain" and "tls_path" options via one method or the other, or the server cannot start!
|
||||
}}
|
||||
|
||||
<!-- deno-fmt-ignore-end -->
|
||||
|
||||
The following is a commented example configuration.
|
||||
|
||||
```toml
|
||||
{{#rustdoc_include ../../examples/server_container.toml}}
|
||||
|
@ -23,7 +40,7 @@ This example is located in
|
|||
{{#template templates/kani-warning.md
|
||||
imagepath=images
|
||||
title=Warning!
|
||||
text=You MUST set the `domain` name correctly, aligned with your `origin`, else the server may refuse to start or some features (e.g. webauthn, oauth) may not work correctly!
|
||||
text=You MUST set the "domain" name correctly, aligned with your "origin", else the server may refuse to start or some features (e.g. WebAuthn, OAuth2) may not work correctly!
|
||||
}}
|
||||
|
||||
<!-- deno-fmt-ignore-end -->
|
||||
|
@ -40,8 +57,8 @@ docker run --rm -i -t -v kanidmd:/data \
|
|||
|
||||
## Run the Server
|
||||
|
||||
Now we can run the server so that it can accept connections. This defaults to using
|
||||
`-c /data/server.toml`.
|
||||
Now we can run the server so that it can accept connections. The container defaults to using a
|
||||
configuration file in `/data/server.toml`.
|
||||
|
||||
```bash
|
||||
docker run -p 443:8443 -v kanidmd:/data kanidm/server:latest
|
||||
|
@ -50,12 +67,14 @@ docker run -p 443:8443 -v kanidmd:/data kanidm/server:latest
|
|||
### Using the NET\_BIND\_SERVICE capability
|
||||
|
||||
If you plan to run without using docker port mapping or some other reverse proxy, and your
|
||||
bindaddress or ldapbindaddress port is less than `1024` you will need the `NET_BIND_SERVICE` in
|
||||
`bindaddress` or `ldapbindaddress` port is less than `1024` you will need the `NET_BIND_SERVICE` in
|
||||
docker to allow these port binds. You can add this with `--cap-add` in your docker run command.
|
||||
|
||||
```bash
|
||||
docker run --cap-add NET_BIND_SERVICE --network [host OR macvlan OR ipvlan] \
|
||||
-v kanidmd:/data kanidm/server:latest
|
||||
docker run --cap-add NET_BIND_SERVICE \
|
||||
--network [host OR macvlan OR ipvlan] \
|
||||
-v kanidmd:/data \
|
||||
kanidm/server:latest
|
||||
```
|
||||
|
||||
<!-- deno-fmt-ignore-start -->
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
# - set up a test oauth2 rp (https://kanidm.com)
|
||||
# - prompt to reset testuser's creds online
|
||||
|
||||
set -e
|
||||
|
||||
if [ -n "${BUILD_MODE}" ]; then
|
||||
BUILD_MODE="--${BUILD_MODE}"
|
||||
else
|
||||
|
@ -83,13 +81,16 @@ if [ "${REMOVE_TEST_DB}" -eq 1 ]; then
|
|||
rm /tmp/kanidm/kanidm.db || true
|
||||
fi
|
||||
|
||||
export KANIDM_CONFIG="../../examples/insecure_server.toml"
|
||||
IDM_ADMIN_USER="idm_admin@localhost"
|
||||
|
||||
|
||||
echo "Resetting the idm_admin user..."
|
||||
IDM_ADMIN_PASS=$(${KANIDMD} recover-account idm_admin -o json 2>&1 | grep password | jq -r .password)
|
||||
IDM_ADMIN_PASS_RAW="$(${KANIDMD} recover-account idm_admin -o json 2>&1)"
|
||||
IDM_ADMIN_PASS="$(echo "${IDM_ADMIN_PASS_RAW}" | grep password | jq -r .password)"
|
||||
if [ -z "${IDM_ADMIN_PASS}" ] || [ "${IDM_ADMIN_PASS}" == "null " ]; then
|
||||
echo "Failed to reset idm_admin password!"
|
||||
echo "Raw output:"
|
||||
echo "${IDM_ADMIN_PASS_RAW}"
|
||||
exit 1
|
||||
fi
|
||||
echo "idm_admin pass: '${IDM_ADMIN_PASS}'"
|
||||
|
|
|
@ -25,16 +25,18 @@ if [ ! -f "run_insecure_dev_server.sh" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
export KANIDM_CONFIG="../../examples/insecure_server.toml"
|
||||
|
||||
mkdir -p /tmp/kanidm/client_ca
|
||||
|
||||
echo "Generating certificates..."
|
||||
cargo run --bin kanidmd --release cert-generate --config ../../examples/insecure_server.toml
|
||||
cargo run --bin kanidmd --release cert-generate
|
||||
|
||||
echo "Making sure it runs with the DB..."
|
||||
cargo run --bin kanidmd --release recover-account idm_admin -o json --config ../../examples/insecure_server.toml
|
||||
cargo run --bin kanidmd --release recover-account idm_admin -o json
|
||||
|
||||
echo "Running the server..."
|
||||
cargo run --bin kanidmd --release server --config ../../examples/insecure_server.toml &
|
||||
cargo run --bin kanidmd --release server &
|
||||
KANIDMD_PID=$!
|
||||
echo "Kanidm PID: ${KANIDMD_PID}"
|
||||
|
||||
|
|
|
@ -80,25 +80,27 @@ pub struct TlsConfiguration {
|
|||
pub client_ca: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// This is the Server Configuration as read from `server.toml`.
|
||||
/// This is the Server Configuration as read from `server.toml` or environment variables.
|
||||
///
|
||||
/// Fields noted as "REQUIRED" are required for the server to start, even if they show as optional due to how file parsing works.
|
||||
///
|
||||
/// If you want to set these as environment variables, prefix them with `KANIDM_` and they will be picked up. This does not include replication peer config.
|
||||
///
|
||||
/// NOTE: not all flags or values from the internal [Configuration] object are exposed via this structure
|
||||
/// to prevent certain settings being set (e.g. integration test modes)
|
||||
///
|
||||
/// If you want to set these as environment variables, prefix them with `KANIDM_` and they will be picked up. This doesn't include replication peer config.
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerConfig {
|
||||
/// Kanidm Domain, eg `kanidm.example.com`.
|
||||
pub domain: String,
|
||||
/// The user-facing HTTPS URL for this server, eg <https://idm.example.com>
|
||||
/// *REQUIRED* - Kanidm Domain, eg `kanidm.example.com`.
|
||||
pub domain: Option<String>,
|
||||
/// *REQUIRED* - The user-facing HTTPS URL for this server, eg <https://idm.example.com>
|
||||
// TODO -this should be URL
|
||||
pub origin: String,
|
||||
pub origin: Option<String>,
|
||||
/// File path of the database file
|
||||
pub db_path: String,
|
||||
/// The file path to the TLS Certificate Chain
|
||||
pub db_path: Option<String>,
|
||||
/// *REQUIRED* - The file path to the TLS Certificate Chain
|
||||
pub tls_chain: Option<String>,
|
||||
/// The file path to the TLS Private Key
|
||||
/// *REQUIRED* - The file path to the TLS Private Key
|
||||
pub tls_key: Option<String>,
|
||||
|
||||
/// The directory path of the client ca and crl dir.
|
||||
|
@ -115,7 +117,7 @@ pub struct ServerConfig {
|
|||
/// If unset, the LDAP server will be disabled.
|
||||
pub ldapbindaddress: Option<String>,
|
||||
|
||||
/// The role of this server, one of write_replica, write_replica_no_ui, read_only_replica
|
||||
/// The role of this server, one of write_replica, write_replica_no_ui, read_only_replica, defaults to [ServerRole::WriteReplica]
|
||||
#[serde(default)]
|
||||
pub role: ServerRole,
|
||||
/// The log level, one of info, debug, trace. Defaults to "info" if not set.
|
||||
|
@ -129,7 +131,8 @@ pub struct ServerConfig {
|
|||
|
||||
/// The filesystem type, either "zfs" or "generic". Defaults to "generic" if unset. I you change this, run a database vacuum.
|
||||
pub db_fs_type: Option<kanidm_proto::internal::FsType>,
|
||||
/// The path to the "admin" socket, used for local communication when performing cer ain server control tasks.
|
||||
|
||||
/// The path to the "admin" socket, used for local communication when performing certain server control tasks. Default is set on build, based on the system target.
|
||||
pub adminbindpath: Option<String>,
|
||||
|
||||
/// Don't touch this unless you know what you're doing!
|
||||
|
@ -139,43 +142,101 @@ pub struct ServerConfig {
|
|||
#[serde(rename = "replication")]
|
||||
/// Replication configuration, this is a development feature and not yet ready for production use.
|
||||
pub repl_config: Option<ReplicationConfiguration>,
|
||||
/// An optional OpenTelemetry collector (GRPC) url to send trace and log data to, eg http://localhost:4317
|
||||
/// An optional OpenTelemetry collector (GRPC) url to send trace and log data to, eg `http://localhost:4317`. If not set, disables the feature.
|
||||
pub otel_grpc_url: Option<String>,
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
/// loads the configuration file from the path specified, then overlays fields from environment variables starting with `KANIDM_``
|
||||
pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Self, std::io::Error> {
|
||||
let mut f = File::open(config_path.as_ref()).map_err(|e| {
|
||||
eprintln!("Unable to open config file [{:?}] 🥺", e);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(config_path.as_ref());
|
||||
eprintln!("{}", diag);
|
||||
e
|
||||
})?;
|
||||
pub fn new<P: AsRef<Path>>(config_path: Option<P>) -> Result<Self, std::io::Error> {
|
||||
// start with a base config
|
||||
let mut config = ServerConfig::default();
|
||||
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).map_err(|e| {
|
||||
eprintln!("unable to read contents {:?}", e);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(config_path.as_ref());
|
||||
eprintln!("{}", diag);
|
||||
e
|
||||
})?;
|
||||
if let Some(config_path) = config_path {
|
||||
// see if we can load it from the config file you asked for
|
||||
if config_path.as_ref().exists() {
|
||||
eprintln!("📜 Using config file: {:?}", config_path.as_ref());
|
||||
let mut f: File = File::open(config_path.as_ref()).map_err(|e| {
|
||||
eprintln!("Unable to open config file [{:?}] 🥺", e);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(config_path.as_ref());
|
||||
eprintln!("{}", diag);
|
||||
e
|
||||
})?;
|
||||
|
||||
let res: ServerConfig = toml::from_str(contents.as_str()).map_err(|e| {
|
||||
eprintln!(
|
||||
"Unable to parse config from '{:?}': {:?}",
|
||||
config_path.as_ref(),
|
||||
e
|
||||
);
|
||||
std::io::Error::new(std::io::ErrorKind::Other, e)
|
||||
})?;
|
||||
let mut contents = String::new();
|
||||
|
||||
let res = res.try_from_env().map_err(|e| {
|
||||
f.read_to_string(&mut contents).map_err(|e| {
|
||||
eprintln!("unable to read contents {:?}", e);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(config_path.as_ref());
|
||||
eprintln!("{}", diag);
|
||||
e
|
||||
})?;
|
||||
|
||||
// if we *can* load the config we'll set config to that.
|
||||
match toml::from_str::<ServerConfig>(contents.as_str()) {
|
||||
Err(err) => {
|
||||
eprintln!(
|
||||
"Unable to parse config from '{:?}': {:?}",
|
||||
config_path.as_ref(),
|
||||
err
|
||||
);
|
||||
}
|
||||
Ok(val) => config = val,
|
||||
};
|
||||
} else {
|
||||
eprintln!("📜 No config file found at {:?}", config_path.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
// build from the environment variables
|
||||
let res = config.try_from_env().map_err(|e| {
|
||||
println!("Failed to use environment variable config: {e}");
|
||||
std::io::Error::new(std::io::ErrorKind::Other, e)
|
||||
})?;
|
||||
|
||||
Ok(res)
|
||||
// check if the required fields are there
|
||||
let mut config_failed = false;
|
||||
if res.domain.is_none() {
|
||||
eprintln!("❌ 'domain' field in server configuration is not set, server cannot start!");
|
||||
config_failed = true;
|
||||
}
|
||||
|
||||
if res.origin.is_none() {
|
||||
eprintln!("❌ 'origin' field in server configuration is not set, server cannot start!");
|
||||
config_failed = true;
|
||||
}
|
||||
|
||||
if res.db_path.is_none() {
|
||||
eprintln!(
|
||||
"❌ 'db_path' field in server configuration is not set, server cannot start!"
|
||||
);
|
||||
config_failed = true;
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
if res.tls_chain.is_none() {
|
||||
eprintln!(
|
||||
"❌ 'tls_chain' field in server configuration is not set, server cannot start!"
|
||||
);
|
||||
config_failed = true;
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
if res.tls_key.is_none() {
|
||||
eprintln!(
|
||||
"❌ 'tls_key' field in server configuration is not set, server cannot start!"
|
||||
);
|
||||
config_failed = true;
|
||||
}
|
||||
|
||||
if config_failed {
|
||||
eprintln!("Failed to parse configuration, server cannot start!");
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Failed to parse configuration, server cannot start!",
|
||||
))
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the ServerConfig from environment variables starting with `KANIDM_`
|
||||
|
@ -202,13 +263,13 @@ impl ServerConfig {
|
|||
|
||||
match key.replace("KANIDM_", "").as_str() {
|
||||
"DOMAIN" => {
|
||||
self.domain = value.to_string();
|
||||
self.domain = Some(value.to_string());
|
||||
}
|
||||
"ORIGIN" => {
|
||||
self.origin = value.to_string();
|
||||
self.origin = Some(value.to_string());
|
||||
}
|
||||
"DB_PATH" => {
|
||||
self.origin = value.to_string();
|
||||
self.origin = Some(value.to_string());
|
||||
}
|
||||
"TLS_CHAIN" => {
|
||||
self.tls_chain = Some(value.to_string());
|
||||
|
|
|
@ -35,6 +35,7 @@ tokio-util = { workspace = true, features = ["codec"] }
|
|||
toml = { workspace = true }
|
||||
opentelemetry = { workspace = true, features = ["logs"] }
|
||||
opentelemetry_api = { workspace = true, features = ["logs"] }
|
||||
tempfile = { workspace = true }
|
||||
tracing = { workspace = true, features = [
|
||||
"max_level_trace",
|
||||
"release_max_level_debug",
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
|
||||
|
||||
use std::fs::{metadata, File};
|
||||
use std::str::FromStr;
|
||||
// This works on both unix and windows.
|
||||
use fs2::FileExt;
|
||||
use kanidm_proto::messages::ConsoleOutputMode;
|
||||
|
@ -268,19 +267,8 @@ async fn kanidm_main() -> ExitCode {
|
|||
//we set up a list of these so we can set the log config THEN log out the errors.
|
||||
let mut config_error: Vec<String> = Vec::new();
|
||||
let mut config = Configuration::new();
|
||||
let cfg_path = opt
|
||||
.commands
|
||||
.commonopt()
|
||||
.config_path
|
||||
.clone()
|
||||
.or_else(|| PathBuf::from_str(env!("KANIDM_DEFAULT_CONFIG_PATH")).ok());
|
||||
|
||||
let Some(cfg_path) = cfg_path else {
|
||||
eprintln!("Unable to start - can not locate any configuration file");
|
||||
return ExitCode::FAILURE;
|
||||
};
|
||||
|
||||
let sconfig = match ServerConfig::new(&cfg_path) {
|
||||
let sconfig = match ServerConfig::new(opt.config_path()) {
|
||||
Ok(c) => Some(c),
|
||||
Err(e) => {
|
||||
config_error.push(format!("Config Parse failure {:?}", e));
|
||||
|
@ -365,85 +353,104 @@ async fn kanidm_main() -> ExitCode {
|
|||
}
|
||||
};
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
let cfg_meta = match metadata(&cfg_path) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for '{}' - {:?}",
|
||||
cfg_path.display(),
|
||||
e
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
if let Some(cfg_path) = opt.config_path() {
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
if let Some(cfg_meta) = match metadata(&cfg_path) {
|
||||
Ok(m) => Some(m),
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for configuration file '{}' - {:?}",
|
||||
cfg_path.display(),
|
||||
e
|
||||
);
|
||||
// return ExitCxode::FAILURE;
|
||||
None
|
||||
}
|
||||
} {
|
||||
if !kanidm_lib_file_permissions::readonly(&cfg_meta) {
|
||||
warn!("permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path"));
|
||||
}
|
||||
|
||||
if cfg_meta.mode() & 0o007 != 0 {
|
||||
warn!("WARNING: {} has 'everyone' permission bits in the mode. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
}
|
||||
|
||||
if cfg_meta.uid() == cuid || cfg_meta.uid() == ceuid {
|
||||
warn!("WARNING: {} owned by the current uid, which may allow file permission changes. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !kanidm_lib_file_permissions::readonly(&cfg_meta) {
|
||||
warn!("permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path"));
|
||||
}
|
||||
|
||||
if cfg_meta.mode() & 0o007 != 0 {
|
||||
warn!("WARNING: {} has 'everyone' permission bits in the mode. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
}
|
||||
|
||||
if cfg_meta.uid() == cuid || cfg_meta.uid() == ceuid {
|
||||
warn!("WARNING: {} owned by the current uid, which may allow file permission changes. This could be a security risk ...",
|
||||
cfg_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the permissions of the files from the configuration.
|
||||
if let Some(db_path) = sconfig.db_path.clone() {
|
||||
#[allow(clippy::expect_used)]
|
||||
let db_pathbuf = PathBuf::from(db_path.as_str());
|
||||
// We can't check the db_path permissions because it may not exist yet!
|
||||
if let Some(db_parent_path) = db_pathbuf.parent() {
|
||||
if !db_parent_path.exists() {
|
||||
warn!(
|
||||
"DB folder {} may not exist, server startup may FAIL!",
|
||||
db_parent_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(&db_pathbuf);
|
||||
info!(%diag);
|
||||
}
|
||||
|
||||
let db_path = PathBuf::from(sconfig.db_path.as_str());
|
||||
// We can't check the db_path permissions because it may not exist yet!
|
||||
if let Some(db_parent_path) = db_path.parent() {
|
||||
if !db_parent_path.exists() {
|
||||
warn!(
|
||||
"DB folder {} may not exist, server startup may FAIL!",
|
||||
db_parent_path.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
let diag = kanidm_lib_file_permissions::diagnose_path(&db_path);
|
||||
info!(%diag);
|
||||
}
|
||||
|
||||
let db_par_path_buf = db_parent_path.to_path_buf();
|
||||
let i_meta = match metadata(&db_par_path_buf) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
let db_par_path_buf = db_parent_path.to_path_buf();
|
||||
let i_meta = match metadata(&db_par_path_buf) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for database folder '{}' - {:?}",
|
||||
&db_par_path_buf.to_str().unwrap_or("invalid file path"),
|
||||
e
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
if !i_meta.is_dir() {
|
||||
error!(
|
||||
"Unable to read metadata for '{}' - {:?}",
|
||||
&db_par_path_buf.to_str().unwrap_or("invalid file path"),
|
||||
e
|
||||
"ERROR: Refusing to run - DB folder {} may not be a directory",
|
||||
db_par_path_buf.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
if !i_meta.is_dir() {
|
||||
error!(
|
||||
"ERROR: Refusing to run - DB folder {} may not be a directory",
|
||||
db_par_path_buf.to_str().unwrap_or("invalid file path")
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if kanidm_lib_file_permissions::readonly(&i_meta) {
|
||||
warn!("WARNING: DB folder permissions on {} indicate it may not be RW. This could cause the server start up to fail!", db_par_path_buf.to_str().unwrap_or("invalid file path"));
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if i_meta.mode() & 0o007 != 0 {
|
||||
warn!("WARNING: DB folder {} has 'everyone' permission bits in the mode. This could be a security risk ...", db_par_path_buf.to_str().unwrap_or("invalid file path"));
|
||||
if kanidm_lib_file_permissions::readonly(&i_meta) {
|
||||
warn!("WARNING: DB folder permissions on {} indicate it may not be RW. This could cause the server start up to fail!", db_par_path_buf.to_str().unwrap_or("invalid file path"));
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if i_meta.mode() & 0o007 != 0 {
|
||||
warn!("WARNING: DB folder {} has 'everyone' permission bits in the mode. This could be a security risk ...", db_par_path_buf.to_str().unwrap_or("invalid file path"));
|
||||
}
|
||||
}
|
||||
config.update_db_path(&db_path);
|
||||
} else {
|
||||
error!("No db_path set in configuration, server startup will FAIL!");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if let Some(origin) = sconfig.origin.clone() {
|
||||
config.update_origin(&origin);
|
||||
} else {
|
||||
error!("No origin set in configuration, server startup will FAIL!");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if let Some(domain) = sconfig.domain.clone() {
|
||||
config.update_domain(&domain);
|
||||
} else {
|
||||
error!("No domain set in configuration, server startup will FAIL!");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
config.update_db_path(sconfig.db_path.as_str());
|
||||
config.update_db_fs_type(&sconfig.db_fs_type);
|
||||
config.update_origin(sconfig.origin.as_str());
|
||||
config.update_domain(sconfig.domain.as_str());
|
||||
config.update_db_arc_size(sconfig.get_db_arc_size());
|
||||
config.update_role(sconfig.role);
|
||||
config.update_output_mode(opt.commands.commonopt().output_mode.to_owned().into());
|
||||
|
@ -461,7 +468,16 @@ async fn kanidm_main() -> ExitCode {
|
|||
| KanidmdOpt::HealthCheck(_) => (),
|
||||
_ => {
|
||||
// Okay - Lets now create our lock and go.
|
||||
let klock_path = format!("{}.klock", sconfig.db_path.as_str());
|
||||
#[allow(clippy::expect_used)]
|
||||
let klock_path = match sconfig.db_path.clone() {
|
||||
Some(val) => format!("{}.klock", val),
|
||||
None => std::env::temp_dir()
|
||||
.join("kanidmd.klock")
|
||||
.to_str()
|
||||
.expect("Unable to create klock path")
|
||||
.to_string(),
|
||||
};
|
||||
|
||||
let flock = match File::create(&klock_path) {
|
||||
Ok(flock) => flock,
|
||||
Err(e) => {
|
||||
|
@ -499,7 +515,7 @@ async fn kanidm_main() -> ExitCode {
|
|||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for '{}' - {:?}",
|
||||
"Unable to read metadata for TLS chain file '{}' - {:?}",
|
||||
&i_path.to_str().unwrap_or("invalid file path"),
|
||||
e
|
||||
);
|
||||
|
@ -520,7 +536,7 @@ async fn kanidm_main() -> ExitCode {
|
|||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for '{}' - {:?}",
|
||||
"Unable to read metadata for TLS key file '{}' - {:?}",
|
||||
&i_path.to_str().unwrap_or("invalid file path"),
|
||||
e
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#[derive(Debug, Args)]
|
||||
struct CommonOpt {
|
||||
/// Path to the server's configuration file. If it does not exist, it will be created.
|
||||
/// Path to the server's configuration file.
|
||||
#[clap(short, long = "config", env = "KANIDM_CONFIG")]
|
||||
config_path: Option<PathBuf>,
|
||||
/// Log format (still in very early development)
|
||||
|
@ -154,6 +154,58 @@ struct KanidmdParser {
|
|||
commands: KanidmdOpt,
|
||||
}
|
||||
|
||||
impl KanidmdParser {
|
||||
/// Returns the configuration path that was specified on the command line, if any.
|
||||
fn config_path(&self) -> Option<PathBuf> {
|
||||
match self.commands {
|
||||
KanidmdOpt::Server(ref c) => c.config_path.clone(),
|
||||
KanidmdOpt::ConfigTest(ref c) => c.config_path.clone(),
|
||||
KanidmdOpt::CertGenerate(ref c) => c.config_path.clone(),
|
||||
KanidmdOpt::RecoverAccount { ref commonopts, .. } => commonopts.config_path.clone(),
|
||||
KanidmdOpt::ShowReplicationCertificate { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
KanidmdOpt::RenewReplicationCertificate { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
KanidmdOpt::RefreshReplicationConsumer { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
KanidmdOpt::DbScan { ref commands } => match commands {
|
||||
DbScanOpt::ListIndexes(ref c) => c.config_path.clone(),
|
||||
DbScanOpt::ListIndex(ref c) => c.commonopts.config_path.clone(),
|
||||
DbScanOpt::ListId2Entry(ref c) => c.config_path.clone(),
|
||||
DbScanOpt::GetId2Entry(ref c) => c.commonopts.config_path.clone(),
|
||||
DbScanOpt::ListIndexAnalysis(ref c) => c.config_path.clone(),
|
||||
DbScanOpt::QuarantineId2Entry { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
DbScanOpt::ListQuarantined { ref commonopts } => commonopts.config_path.clone(),
|
||||
DbScanOpt::RestoreQuarantined { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
},
|
||||
KanidmdOpt::Database { ref commands } => match commands {
|
||||
DbCommands::Vacuum(ref c) => c.config_path.clone(),
|
||||
DbCommands::Backup(ref c) => c.commonopts.config_path.clone(),
|
||||
DbCommands::Restore(ref c) => c.commonopts.config_path.clone(),
|
||||
DbCommands::Verify(ref c) => c.config_path.clone(),
|
||||
DbCommands::Reindex(ref c) => c.config_path.clone(),
|
||||
},
|
||||
KanidmdOpt::DomainSettings { ref commands } => match commands {
|
||||
DomainSettingsCmds::Show { ref commonopts } => commonopts.config_path.clone(),
|
||||
DomainSettingsCmds::Change { ref commonopts } => commonopts.config_path.clone(),
|
||||
DomainSettingsCmds::Raise { ref commonopts } => commonopts.config_path.clone(),
|
||||
DomainSettingsCmds::Remigrate { ref commonopts, .. } => {
|
||||
commonopts.config_path.clone()
|
||||
}
|
||||
},
|
||||
KanidmdOpt::HealthCheck(ref c) => c.commonopts.config_path.clone(),
|
||||
KanidmdOpt::Version(ref c) => c.config_path.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum KanidmdOpt {
|
||||
#[clap(name = "server")]
|
||||
|
|
|
@ -432,7 +432,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
}
|
||||
},
|
||||
(None, None) => {
|
||||
warn!("No client certificate or bearer tokens were supplied");
|
||||
debug!("No client certificate or bearer tokens were supplied");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
}
|
||||
|
@ -464,7 +464,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
}
|
||||
},
|
||||
(None, None) => {
|
||||
warn!("No client certificate or bearer tokens were supplied");
|
||||
debug!("No client certificate or bearer tokens were supplied");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
}
|
||||
|
@ -3810,7 +3810,7 @@ mod tests {
|
|||
Err(e) => {
|
||||
error!("A critical error has occurred! {:?}", e);
|
||||
// Should not occur!
|
||||
panic!();
|
||||
panic!("A critical error has occurred! {:?}", e);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1093,7 +1093,7 @@ fn config_security_checks(cfg_path: &Path) -> bool {
|
|||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Unable to read metadata for '{}' during security checks - {:?}",
|
||||
"Unable to read metadata for config file '{}' during security checks - {:?}",
|
||||
cfg_path_str, e
|
||||
);
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue