diff options
author | BlackDex <[email protected]> | 2022-07-19 18:39:42 +0200 |
---|---|---|
committer | BlackDex <[email protected]> | 2022-07-20 13:29:39 +0200 |
commit | 9a787dd105edeea5fdb309a50f2b47155937c5ed (patch) | |
tree | 003aca0dbcca1e531ad1ee6fe7348047fa4ec7c9 /src/main.rs | |
parent | f1a67663d19013271ebd49f7cd6056f59f6dc3f7 (diff) | |
download | vaultwarden-9a787dd105edeea5fdb309a50f2b47155937c5ed.tar.gz vaultwarden-9a787dd105edeea5fdb309a50f2b47155937c5ed.zip |
Fix persistent folder check within containers
The previous persistent folder check worked by checking if a file
exists. If you used a bind-mount, then this file is not there. But when
using a docker/podman volume those files are copied, and caused the
container to not start.
This change checks the `/proc/self/mountinfo` for a specific patern to
see if the data folder is persistent or not.
Fixes #2622
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/src/main.rs b/src/main.rs index 20f40bc5..ad47f3c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,6 +61,11 @@ use std::{ thread, }; +use tokio::{ + fs::File, + io::{AsyncBufReadExt, BufReader}, +}; + #[macro_use] mod error; mod api; @@ -89,7 +94,7 @@ async fn main() -> Result<(), Error> { let extra_debug = matches!(level, LF::Trace | LF::Debug); - check_data_folder(); + check_data_folder().await; check_rsa_keys().unwrap_or_else(|_| { error!("Error creating keys, exiting..."); exit(1); @@ -286,7 +291,7 @@ fn create_dir(path: &str, description: &str) { create_dir_all(path).expect(&err_msg); } -fn check_data_folder() { +async fn check_data_folder() { let data_folder = &CONFIG.data_folder(); let path = Path::new(data_folder); if !path.exists() { @@ -299,9 +304,10 @@ fn check_data_folder() { exit(1); } - let persistent_volume_check_file = format!("{data_folder}/vaultwarden_docker_persistent_volume_check"); - let check_file = Path::new(&persistent_volume_check_file); - if check_file.exists() && std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err() { + if is_running_in_docker() + && std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err() + && !docker_data_folder_is_persistent(data_folder).await + { error!( "No persistent volume!\n\ ########################################################################################\n\ @@ -314,6 +320,38 @@ fn check_data_folder() { } } +/// Detect when using Docker or Podman the DATA_FOLDER is either a bind-mount or a volume created manually. +/// If not created manually, then the data will not be persistent. +/// A none persistent volume in either Docker or Podman is represented by a 64 alphanumerical string. +/// If we detect this string, we will alert about not having a persistent self defined volume. +/// This probably means that someone forgot to add `-v /path/to/vaultwarden_data/:/data` +async fn docker_data_folder_is_persistent(data_folder: &str) -> bool { + if let Ok(mountinfo) = File::open("/proc/self/mountinfo").await { + // Since there can only be one mountpoint to the DATA_FOLDER + // We do a basic check for this mountpoint surrounded by a space. + let data_folder_match = if data_folder.starts_with('/') { + format!(" {data_folder} ") + } else { + format!(" /{data_folder} ") + }; + let mut lines = BufReader::new(mountinfo).lines(); + while let Some(line) = lines.next_line().await.unwrap_or_default() { + // Only execute a regex check if we find the base match + if line.contains(&data_folder_match) { + let re = regex::Regex::new(r"/volumes/[a-z0-9]{64}/_data /").unwrap(); + if re.is_match(&line) { + return false; + } + // If we did found a match for the mountpoint, but not the regex, then still stop searching. + break; + } + } + } + // In all other cases, just assume a true. + // This is just an informative check to try and prevent data loss. + true +} + fn check_rsa_keys() -> Result<(), crate::error::Error> { // If the RSA keys don't exist, try to create them let priv_path = CONFIG.private_rsa_key(); |