Skip to main content

hashiverse_server_lib/server/
passphrase.rs

1//! # Passphrase resolution for server secrets
2//!
3//! Finds the operator's passphrase (used to decrypt the persisted
4//! [`hashiverse_lib::tools::server_id::ServerId`]) in a platform-agnostic way, looking
5//! in this order:
6//!
7//! 1. an explicit file path supplied on the command line,
8//! 2. standard container-secret mounts (`/run/secrets/`, `/mnt/secrets/`,
9//!    `/etc/secrets/`) — Kubernetes, Docker Swarm and Podman all land here,
10//! 3. an environment variable — still supported for legacy non-container deployments.
11//!
12//! The resolved passphrase is wrapped in `secrecy::SecretString` so it is zeroised on
13//! drop and never accidentally logged.
14
15use std::fs;
16use secrecy::SecretString;
17
18pub fn get_passphrase(passphrase_path: Option<String>) -> anyhow::Result<SecretString> {
19    fn get_passphrase_from_file_if_exists(path: &str) -> Option<SecretString> {
20        let contents = fs::read_to_string(path);
21        match contents {
22            Ok(contents) => Some(SecretString::new(Box::from(contents))),
23            Err(_) => None
24        }
25    }
26
27    // If the user has specified a container-injected passphrase, use that or die
28    if let Some(passphrase_path) = passphrase_path {
29        let passphrase = get_passphrase_from_file_if_exists(&passphrase_path);
30        match passphrase {
31            Some(passphrase) => return Ok(passphrase),
32            None => anyhow::bail!("no passphrase found at {}", passphrase_path)
33        }
34    }
35
36    // Else try the most secure routes - a secret file mount-injected by the container
37    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/run/secrets/hashiverse_passphrase") { return Ok(passphrase); }
38    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/run/secrets/HASHIVERSE_PASSPHRASE") { return Ok(passphrase); }
39    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/mnt/secrets/hashiverse_passphrase") { return Ok(passphrase); }
40    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/mnt/secrets/HASHIVERSE_PASSPHRASE") { return Ok(passphrase); }
41    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/etc/secrets/hashiverse_passphrase") { return Ok(passphrase); }
42    if let Some(passphrase) = get_passphrase_from_file_if_exists("	/etc/secrets/HASHIVERSE_PASSPHRASE") { return Ok(passphrase); }
43    if let Some(passphrase) = get_passphrase_from_file_if_exists("	./.hashiverse_passphrase") { return Ok(passphrase); }
44    if let Some(passphrase) = get_passphrase_from_file_if_exists("	./.HASHIVERSE_PASSPHRASE") { return Ok(passphrase); }
45
46    // Else try an env variable
47    if let Ok(passphrase) = std::env::var("HASHIVERSE_PASSPHRASE") { return Ok(SecretString::new(Box::from(passphrase))); }
48
49    // Error!
50    anyhow::bail!("no passphrase found - please (at worst) set the HASHIVERSE_PASSPHRASE environment variable to something memorable");
51}