Skip to content
Snippets Groups Projects
Verified Commit c28d3f0e authored by David Runge's avatar David Runge :chipmunk:
Browse files

feat: Add `signstar-common` crate to provide common facilities


- Adds all public data required for the `signstar-configure-build`
  crate, as it will be shared by other crates.
- Adds NetHSM specific defaults.
- Adds basic configuration file retrieval and directory handling for
  Signstar hosts.
- Adds administrative credentials file retrieval and directory handling
  for Signstar hosts.

Signed-off-by: default avatarDavid Runge <dvzrv@archlinux.org>
parent 13c48522
No related branches found
No related tags found
1 merge request!181feat: Add `signstar-common` crate to provide common facilities
......@@ -3,3 +3,7 @@
# an URL fragment that's used in format! macro
# see: https://github.com/lycheeverse/lychee/issues/1492
https://raw.githubusercontent.com/Nitrokey/nethsm-sdk-py/main/tests/%7B%7D
# URLs that only become available after release of a component
https://signstar.archlinux.page/rustdoc/signstar_common/
https://docs.rs/signstar_common/latest/signstar_common/
......@@ -3133,6 +3133,14 @@ dependencies = [
"rand_core",
]
[[package]]
name = "signstar-common"
version = "0.1.0"
dependencies = [
"nethsm",
"thiserror 2.0.11",
]
[[package]]
name = "signstar-configure-build"
version = "0.1.2"
......
......@@ -7,6 +7,7 @@ members = [
"nethsm-config",
"nethsm-tests",
"signstar-configure-build",
"signstar-common",
"signstar-request-signature",
]
......@@ -31,6 +32,7 @@ serde = { version = "1.0.215", features = ["derive"] }
# Then adjust the tests in signstar-request-signature/src/lib.rs to additionally test
# inputs that reference the "old_sha2".
sha2 = "0.11.0-pre.4"
signstar-common = { path = "signstar-common", version = "0.1.0" }
signstar-request-signature = { path = "signstar-request-signature", version = "0.1.0" }
strum = { version = "0.27.0", features = ["derive"] }
testdir = "0.9.3"
......
[package]
authors.workspace = true
description = "Common components for Signstar libraries and command-line interfaces"
edition.workspace = true
homepage.workspace = true
keywords = ["user", "signstar", "nethsm"]
license.workspace = true
name = "signstar-common"
repository.workspace = true
version = "0.1.0"
[dependencies]
nethsm.workspace = true
thiserror.workspace = true
# Signstar common
Shared components and data types for Signstar tools and libraries
## Documentation
- <https://signstar.archlinux.page/rustdoc/signstar_common/> for development version of the crate
- <https://docs.rs/signstar_common/latest/signstar_common/> for released versions of the crate
## Contributing
Please refer to the [contributing guidelines] to learn how to contribute to this project.
## License
This project may be used under the terms of the [Apache-2.0] or [MIT] license.
Changes to this project - unless stated otherwise - automatically fall under the terms of both of the aforementioned licenses.
[Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0
[MIT]: https://opensource.org/licenses/MIT
[contributing guidelines]: ../CONTRIBUTING.md
//! Data and functions for using administrative credentials on a Signstar host.
//!
//! # Examples
//!
//! ```
//! use signstar_common::admin_credentials::get_credentials_dir;
//!
//! // Get the directory path in which administrative credentials reside.
//! println!("{:?}", get_credentials_dir());
//! ```
use std::{
fs::{Permissions, create_dir_all, set_permissions},
os::unix::fs::{PermissionsExt, chown},
path::PathBuf,
};
use crate::common::{CREDENTIALS_DIR_MODE, get_data_home};
/// File name of plaintext administrative credentials.
const PLAINTEXT_CREDENTIALS_FILE: &str = "admin-credentials.toml";
/// File name of systemd-creds encrypted administrative credentials.
const SYSTEMD_CREDS_CREDENTIALS_FILE: &str = "admin-credentials.creds";
/// The directory for administrative credentials (encrypted and unencrypted).
const CREDENTIALS_DIR: &str = "creds/";
/// An error that may occur when handling credentials.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Applying permissions to a file failed.
#[error("Unable to apply permissions {permissions} to {path}:\n{source}")]
ApplyPermissions {
permissions: u32,
path: PathBuf,
source: std::io::Error,
},
/// No plaintext administrative credentials file can be found
#[error("Unable to create directory {dir}:\n{source}")]
CreateDirectory {
dir: &'static str,
source: std::io::Error,
},
/// The ownership of a directory can not be set.
#[error("Ownership of directory {dir} can not be changed to user {system_user}: {source}")]
DirChangeOwner {
dir: PathBuf,
system_user: String,
source: std::io::Error,
},
}
/// Returns the path of the directory in which administrative credentials reside.
pub fn get_credentials_dir() -> PathBuf {
get_data_home().join(PathBuf::from(CREDENTIALS_DIR))
}
/// Returns the file path for plaintext administrative credentials.
pub fn get_plaintext_credentials_file() -> PathBuf {
get_credentials_dir().join(PathBuf::from(PLAINTEXT_CREDENTIALS_FILE))
}
/// Returns the file path for systemd-creds encrypted administrative credentials.
pub fn get_systemd_creds_credentials_file() -> PathBuf {
get_credentials_dir().join(PathBuf::from(SYSTEMD_CREDS_CREDENTIALS_FILE))
}
/// Creates the directory for administrative credentials.
///
/// # Errors
///
/// Returns an error if the directory or one of its parents can not be created.
/// Refer to [`create_dir_all`] for further information on failure scenarios.
pub fn create_credentials_dir() -> Result<(), Error> {
let credentials_dir = get_credentials_dir();
create_dir_all(credentials_dir.as_path()).map_err(|source| Error::CreateDirectory {
dir: CREDENTIALS_DIR,
source,
})?;
// Set the permissions of the credentials directory to `CREDENTIALS_DIR_MODE`.
set_permissions(
credentials_dir.as_path(),
Permissions::from_mode(CREDENTIALS_DIR_MODE),
)
.map_err(|source| Error::ApplyPermissions {
permissions: CREDENTIALS_DIR_MODE,
path: credentials_dir.clone(),
source,
})?;
// Recursively chown all directories to root, until `DATA_HOME` is
// reached.
let data_home = get_data_home();
let mut chown_dir = credentials_dir.clone();
while chown_dir != data_home {
chown(&chown_dir, Some(0), Some(0)).map_err(|source| Error::DirChangeOwner {
dir: chown_dir.to_path_buf(),
system_user: "root".to_string(),
source,
})?;
if let Some(parent) = &chown_dir.parent() {
chown_dir = parent.to_path_buf()
} else {
break;
}
}
Ok(())
}
//! Common data for all Signstar functionalities.
//!
//! # Examples
//!
//! ```
//! use signstar_common::common::get_data_home;
//!
//! // Get the directory below which all Signstar related data is stored.
//! println!("{:?}", get_data_home());
//! ```
use std::path::PathBuf;
/// The directory below which o store all Signstar related data.
const DATA_HOME: &str = "/var/lib/signstar/";
/// The file mode of directories containing credentials.
pub const CREDENTIALS_DIR_MODE: u32 = 0o100700;
/// The file mode of secret files.
pub const SECRET_FILE_MODE: u32 = 0o100600;
/// Get the directory below which all Signstar related data is stored.
pub fn get_data_home() -> PathBuf {
PathBuf::from(DATA_HOME)
}
//! Default locations for Signstar configuration files.
//!
//! # Examples
//!
//! ```
//! use signstar_common::config::{
//! get_config_file_or_default,
//! get_config_file_paths,
//! get_config_file,
//! get_default_config_dir_path,
//! get_default_config_file_path,
//! get_etc_override_config_file_path,
//! get_etc_override_dir_path,
//! get_run_override_config_file_path,
//! get_run_override_dir_path,
//! get_usr_local_override_config_file_path,
//! get_usr_local_override_dir_path,
//! };
//!
//! // Get directory paths for Signstar configuration files.
//! println!("{:?}", get_etc_override_dir_path());
//! println!("{:?}", get_run_override_dir_path());
//! println!("{:?}", get_usr_local_override_dir_path());
//! println!("{:?}", get_default_config_dir_path());
//!
//! // Get file paths for Signstar configuration files.
//! println!("{:?}", get_etc_override_config_file_path());
//! println!("{:?}", get_run_override_config_file_path());
//! println!("{:?}", get_usr_local_override_config_file_path());
//! println!("{:?}", get_default_config_file_path());
//!
//! // Get the first config file found, according to directory precedence.
//! println!("{:?}", get_config_file());
//!
//! // Get the first config file found, according to directory precedence, or the default if none are found.
//! println!("{:?}", get_config_file_or_default());
//!
//! // Get all configuration file paths, sorted by directory precedence.
//! println!("{:?}", get_config_file_paths());
//! ```
use std::{fs::create_dir_all, path::PathBuf};
/// The default config directory below "/usr" for Signstar hosts.
const DEFAULT_CONFIG_DIR: &str = "/usr/share/signstar/";
/// The override config directory below "/etc" for Signstar hosts.
const ETC_OVERRIDE_CONFIG_DIR: &str = "/etc/signstar/";
/// The override config directory below "/run" for Signstar hosts.
const RUN_OVERRIDE_CONFIG_DIR: &str = "/run/signstar/";
/// The override config directory below "/usr/local" for Signstar hosts.
const USR_LOCAL_OVERRIDE_CONFIG_DIR: &str = "/usr/local/share/signstar/";
/// The filename of a Signstar configuration file.
const CONFIG_FILE: &str = "config.toml";
/// An error that may occur when handling configuration directories or files.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// A directory can not be created.
#[error("Unable to create directory {dir}:\n{source}")]
CreateDirectory { dir: String, source: std::io::Error },
}
/// Returns the first Signstar configuration file available, or [`None`] if none found.
///
/// Considers files named `config.toml` in the following directories in descending priority:
/// - `/etc/signstar`
/// - `/run/signstar`
/// - `/usr/local/share/signstar`
/// - `/usr/share/signstar`
///
/// The first existing file is returned.
/// If no file is found [`None`] is returned.
pub fn get_config_file() -> Option<PathBuf> {
[
get_etc_override_config_file_path(),
get_run_override_config_file_path(),
get_usr_local_override_config_file_path(),
get_default_config_file_path(),
]
.into_iter()
.find(|file| file.is_file())
}
/// Returns the first Signstar configuration file available, or the default if none found.
///
/// Considers files named `config.toml` in the following directories in descending priority:
/// - `/etc/signstar`
/// - `/run/signstar`
/// - `/usr/local/share/signstar`
/// - `/usr/share/signstar`
///
/// The first existing file is returned.
/// If no file is found, the default location `/usr/share/signstar/config.toml` is returned.
pub fn get_config_file_or_default() -> PathBuf {
let Some(config) = get_config_file() else {
return get_default_config_file_path();
};
config
}
/// Returns a list of all configuration file locations, sorted by precedence.
pub fn get_config_file_paths() -> Vec<PathBuf> {
vec![
get_etc_override_config_file_path(),
get_run_override_config_file_path(),
get_usr_local_override_config_file_path(),
get_default_config_file_path(),
]
}
/// Returns the file path of the configuration file override below /etc.
pub fn get_etc_override_config_file_path() -> PathBuf {
PathBuf::from([ETC_OVERRIDE_CONFIG_DIR, CONFIG_FILE].concat())
}
/// Returns the directory path of the configuration override directory below /etc.
pub fn get_etc_override_dir_path() -> PathBuf {
PathBuf::from(ETC_OVERRIDE_CONFIG_DIR)
}
/// Returns the file path of the configuration file override below /run.
pub fn get_run_override_config_file_path() -> PathBuf {
PathBuf::from([RUN_OVERRIDE_CONFIG_DIR, CONFIG_FILE].concat())
}
/// Returns the directory path of the configuration override directory below /run.
pub fn get_run_override_dir_path() -> PathBuf {
PathBuf::from(RUN_OVERRIDE_CONFIG_DIR)
}
/// Returns the file path of the configuration file override below /usr/local.
pub fn get_usr_local_override_config_file_path() -> PathBuf {
PathBuf::from([USR_LOCAL_OVERRIDE_CONFIG_DIR, CONFIG_FILE].concat())
}
/// Returns the directory path of the configuration override directory below /usr/local.
pub fn get_usr_local_override_dir_path() -> PathBuf {
PathBuf::from(USR_LOCAL_OVERRIDE_CONFIG_DIR)
}
/// Returns the file path of the default configuration file /usr.
pub fn get_default_config_file_path() -> PathBuf {
PathBuf::from([DEFAULT_CONFIG_DIR, CONFIG_FILE].concat())
}
/// Returns the directory path of the default configuration directory below /usr.
pub fn get_default_config_dir_path() -> PathBuf {
PathBuf::from(DEFAULT_CONFIG_DIR)
}
/// Creates the default configuration directory below /usr.
///
/// # Errors
///
/// Returns an error if the directory or one of its parents can not be created.
/// Refer to [`create_dir_all`] for further information on failure scenarios.
pub fn create_default_config_dir() -> Result<(), Error> {
create_dir_all(get_default_config_dir_path()).map_err(|source| Error::CreateDirectory {
dir: DEFAULT_CONFIG_DIR.to_string(),
source,
})
}
/// Creates the configuration override dir below /etc.
///
/// # Errors
///
/// Returns an error if the directory or one of its parents can not be created.
/// Refer to [`create_dir_all`] for further information on failure scenarios.
pub fn create_etc_override_config_dir() -> Result<(), Error> {
create_dir_all(get_etc_override_dir_path()).map_err(|source| Error::CreateDirectory {
dir: ETC_OVERRIDE_CONFIG_DIR.to_string(),
source,
})
}
/// Creates the configuration override dir below /run.
///
/// # Errors
///
/// Returns an error if the directory or one of its parents can not be created.
/// Refer to [`create_dir_all`] for further information on failure scenarios.
pub fn create_run_override_config_dir() -> Result<(), Error> {
create_dir_all(get_run_override_dir_path()).map_err(|source| Error::CreateDirectory {
dir: RUN_OVERRIDE_CONFIG_DIR.to_string(),
source,
})
}
/// Creates the configuration override dir below /usr/local.
///
/// # Errors
///
/// Returns an error if the directory or one of its parents can not be created.
/// Refer to [`create_dir_all`] for further information on failure scenarios.
pub fn create_usr_local_override_config_dir() -> Result<(), Error> {
create_dir_all(get_usr_local_override_dir_path()).map_err(|source| Error::CreateDirectory {
dir: USR_LOCAL_OVERRIDE_CONFIG_DIR.to_string(),
source,
})
}
//! Common components and data for Signstar crates.
pub mod admin_credentials;
pub mod common;
pub mod config;
pub mod nethsm;
pub mod ssh;
pub mod system_user;
//! Defaults for NetHSM backends.
use std::net::Ipv4Addr;
use nethsm::LogLevel;
/// The default admin user name of newly provisioned NetHSM.
pub const USER_DEFAULT_ADMIN: &str = "admin";
/// The default IP address of an unprovisioned NetHSM.
pub const NETWORK_DEFAULT_IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(192, 168, 1, 1);
/// The default netmask of an unprovisioned NetHSM.
pub const NETWORK_DEFAULT_NETMASK: Ipv4Addr = Ipv4Addr::new(255, 255, 255, 0);
/// The default gateway of an unprovisioned NetHSM.
pub const NETWORK_DEFAULT_GATEWAY: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
/// The default logging IP address of an unprovisioned NetHSM.
pub const LOGGING_DEFAULT_IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
/// The default logging port of an unprovisioned NetHSM.
pub const LOGGING_DEFAULT_PORT: u32 = 514;
/// The default logging level of an unprovisioned NetHSM.
pub const LOGGING_DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info;
//! Defaults for SSH.
//!
//! # Examples
//!
//! ```
//! use signstar_common::ssh::{get_ssh_authorized_key_base_dir, get_sshd_config_dropin_dir};
//!
//! // Get directory path for SSH authorized_keys files for Signstar users.
//! println!("{:?}", get_ssh_authorized_key_base_dir());
//!
//! // Get directory path for sshd_config drop-in files.
//! println!("{:?}", get_sshd_config_dropin_dir());
//! ```
use std::path::PathBuf;
/// The base directory below which SSH authorized_keys files for users are located.
const SSH_AUTHORIZED_KEY_BASE_DIR: &str = "/etc/ssh/";
/// The directory below which sshd_config drop-in files are located.
const SSHD_CONFIG_DROPIN_DIR: &str = "/etc/ssh/sshd_config.d/";
/// Returns the directory path below which SSH authorized_keys files for Signstar users are located.
pub fn get_ssh_authorized_key_base_dir() -> PathBuf {
PathBuf::from(SSH_AUTHORIZED_KEY_BASE_DIR)
}
/// Returns the directory path below which SSH authorized_keys files for Signstar users are located.
pub fn get_sshd_config_dropin_dir() -> PathBuf {
PathBuf::from(SSHD_CONFIG_DROPIN_DIR)
}
//! Defaults for system users.
//!
//! ```
//! use signstar_common::system_user::{get_home_base_dir_path, get_relative_user_secrets_dir};
//!
//! // Get the base directory below which Signstar system user homes are located.
//! println!("{:?}", get_home_base_dir_path());
//!
//! // Get the relative directory below which Signstar secrets are located per system user.
//! println!("{:?}", get_relative_user_secrets_dir());
//! ```
use std::path::PathBuf;
use crate::common::get_data_home;
/// The relative base directory below which system user homes are located.
///
/// This directory resides relative to the data home on the system.
const HOME_BASE_DIR: &str = "home/";
/// The directory name below which credentials files are stored.
///
/// The directory is evaluated relative to a user's home.
const USER_SECRETS_DIR: &str = ".local/state/signstar/secrets/";
/// The file extension of plaintext credential files.
const PLAINTEXT_SECRETS_EXTENSION: &str = "txt";
/// The file extension of systemd-creds encrypted credential files.
const SYSTEMD_CREDS_SECRETS_EXTENSION: &str = "creds";
/// Returns the base directory below which Signstar system user homes are located.
pub fn get_home_base_dir_path() -> PathBuf {
get_data_home().join(PathBuf::from(HOME_BASE_DIR))
}
/// Returns the relative directory below which Signstar secrets are located per system user.
pub fn get_relative_user_secrets_dir() -> PathBuf {
PathBuf::from(USER_SECRETS_DIR)
}
/// Returns the path to the secrets directory for a specific system user.
pub fn get_user_secrets_dir(system_user: &str) -> PathBuf {
get_home_base_dir_path()
.join(PathBuf::from(system_user))
.join(get_relative_user_secrets_dir())
}
/// Returns the path to a plaintext secrets file for a system user and backend user.
pub fn get_plaintext_secret_file(system_user: &str, backend_user: &str) -> PathBuf {
get_user_secrets_dir(system_user).join(PathBuf::from(
[backend_user, ".", PLAINTEXT_SECRETS_EXTENSION].concat(),
))
}
/// Returns the path to a systemd-creds encrypted secrets file for a system user and backend user.
pub fn get_systemd_creds_secret_file(system_user: &str, backend_user: &str) -> PathBuf {
get_user_secrets_dir(system_user).join(PathBuf::from(
[backend_user, ".", SYSTEMD_CREDS_SECRETS_EXTENSION].concat(),
))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment