diff --git a/Cargo.lock b/Cargo.lock index fd03711..b9d5556 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,6 +90,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -204,6 +213,26 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.85", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -281,6 +310,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -336,6 +374,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "console" version = "0.15.8" @@ -713,6 +762,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "hashbrown" version = "0.14.5" @@ -918,6 +973,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "js-sys" version = "0.3.72" @@ -936,12 +1000,28 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libm" version = "0.2.11" @@ -970,6 +1050,17 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loopdev-3" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90a97d7a5124296ee9124a815acdc3dc4a91f577b72812b3f1f99bb959b46e8d" +dependencies = [ + "bindgen", + "errno", + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1305,6 +1396,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1553,6 +1673,17 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smart-default" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + [[package]] name = "spdlog-macros" version = "0.1.0" @@ -1646,6 +1777,20 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sys-mount" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6acb8bb63826062d5a44b68298cf2e25b84bc151bc0c31c35a83b61f818682a" +dependencies = [ + "bitflags", + "libc", + "loopdev-3", + "smart-default", + "thiserror", + "tracing", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -1741,6 +1886,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "type-map" version = "0.5.0" @@ -1814,6 +1990,7 @@ dependencies = [ "sha2", "spdlog-rs", "subtle", + "sys-mount", "tempdir", "toml 0.8.19", ] diff --git a/Cargo.toml b/Cargo.toml index 668d66b..9c46e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,6 @@ serde = "1.0.210" sha2 = "0.10.8" spdlog-rs = "0.3.13" subtle = "2.6.1" +sys-mount = "3.0.1" tempdir = "0.3.7" toml = "0.8.19" diff --git a/TODO.md b/TODO.md index be0609c..05d3413 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ - [ ] vaultix.d in ramfs -- [ ] age plugin +- [ ] vaultix{,.d} permission +- [x] age plugin - [ ] check command - [x] should get entire `Secret` when deploy - [x] [renc] calc hash and skip unchanged diff --git a/flake.nix b/flake.nix index 7813eb7..f37c79a 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,9 @@ in (buildPackage { src = craneLib.cleanCargoSource ./.; + nativeBuildInputs = [ + pkgs.rustPlatform.bindgenHook + ]; meta.mainProgram = "vaultix"; }); @@ -76,6 +79,8 @@ inputsFrom = [ pkgs.vaultix ]; + + RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}"; buildInputs = with pkgs; [ just nushell diff --git a/justfile b/justfile index 3417857..f31a851 100644 --- a/justfile +++ b/justfile @@ -15,3 +15,8 @@ eval-json: init-storage: mkdir -p test/secrets/renced/tester +clean-exist-deploy: + #!/usr/bin/env nu + sudo umount /run/vaultix.d + sudo rm -r /run/vaultix.d + sudo rm -r /run/vaultix diff --git a/src/cmd/deploy.rs b/src/cmd/deploy.rs index 6a6667d..1521242 100644 --- a/src/cmd/deploy.rs +++ b/src/cmd/deploy.rs @@ -16,7 +16,8 @@ use crate::{ use age::x25519; use eyre::{eyre, Context, Result}; -use spdlog::{debug, error, info, trace}; +use spdlog::{debug, error, info, trace, warn}; +use sys_mount::{Mount, MountFlags, SupportedFilesystems}; impl HostKey { pub fn get_identity(&self) -> Result { @@ -58,12 +59,31 @@ impl Profile { let mut max = 0; let res = match self.read_decrypted_mount_point() { Err(e) if e.kind() == ErrorKind::NotFound => { - fs::create_dir_all(self.get_decrypted_mount_point_path()).wrap_err_with(|| { + // TODO: noswap mount tmpfs + let support_ramfs = + SupportedFilesystems::new().and_then(|fss| Ok(fss.is_supported("ramfs"))); + if !support_ramfs? { + let err = + "ramfs not supported! Refusing extract secret since it will write to disk"; + error!("{}", err); + return Err(eyre!(err)); + } + let path = self.get_decrypted_mount_point_path(); + info!("creating mount point {}", path.clone()); + fs::create_dir_all(path.clone()).wrap_err_with(|| { format!( "creating decrypted mountpoint: {:?}", self.get_decrypted_mount_point_path() ) - }) + })?; + Mount::builder() + .fstype("ramfs") + .flags(MountFlags::NOSUID) + .data("relatime") + .data("mode=751") + .mount(String::default(), self.get_decrypted_mount_point_path()) + .map(|_| ()) // not needed. + .wrap_err(eyre!("mount tmpfs error")) } Err(e) => { error!("{}", e); @@ -106,8 +126,7 @@ impl Profile { map.into_iter().for_each(|(s, p)| { let _ = ret.insert( s, - p.read_hostpubkey_encrypted_cipher_content() - .expect("read error"), + p.read_hostpubkey_encrypted_cipher_content().expect("error"), ); }); ret @@ -123,9 +142,16 @@ impl Profile { debug!("target extract dir with generation number: {:?}", p); - fs::create_dir_all(&p).map(|_| p).wrap_err(eyre!( - "cannot create target extract dir with generation number" - ))? + fs::create_dir_all(&p) + .map(|_| p) + .wrap_err(eyre!( + "cannot create target extract dir with generation number" + )) + .and_then(|p| { + let _ = fs::set_permissions(&p, Permissions::from_mode(0o751)) + .wrap_err(eyre!("set permission")); + Ok(p) + })? }; let decrypt_host_ident = &self.get_host_key_identity()?; @@ -145,10 +171,7 @@ impl Profile { decrypted }; - info!( - "start deploying {} to generation {}", - n.name, generation_count - ); + info!("{} -> generation {}", n.name, generation_count); let mut the_file = { let mut p = target_extract_dir_with_gen.clone(); p.push(n.name); diff --git a/src/helper/parse_identity.rs b/src/helper/parse_identity.rs index 150cab3..25fc14a 100644 --- a/src/helper/parse_identity.rs +++ b/src/helper/parse_identity.rs @@ -7,29 +7,21 @@ use spdlog::{debug, error, info}; use super::callback::UiCallbacks; -// pub enum Parsed { -// Native(ParsedNativeIdentity), -// } - pub struct ParsedIdentity { identity: Box, recipient: Box, } -// pub struct ParsedPluginIdentity { -// identity: Box>, -// recipient: Box, -// } impl ParsedIdentity { - pub fn new(identity: I, recipient: R) -> Self - where - I: Identity + 'static, - R: Recipient + 'static, - { - Self { - identity: Box::new(identity), - recipient: Box::new(recipient), - } - } + // pub fn new(identity: I, recipient: R) -> Self + // where + // I: Identity + 'static, + // R: Recipient + 'static, + // { + // Self { + // identity: Box::new(identity), + // recipient: Box::new(recipient), + // } + // } pub fn from_exist(identity: Box, recipient: Box) -> Self { Self { identity, @@ -45,21 +37,22 @@ impl ParsedIdentity { } impl MasterIdentity { + // get identiy and recipient from identity file, + // only file that contains info of identity and recip supported at present + // which is expected while using age generated identity pub fn parse( Self { identity, pubkey: _, // not required. trans from prv key so fast. }: &Self, ) -> Result { - // TODO: more case matches - // if age-plugin then get Recipient as recip if identity.is_empty() { return Err(eyre!("No identity found")); } else { - macro_rules! create_entity { - ($method:ident, $err_import:expr, $err_context:expr) => {{ + macro_rules! create { + ($method:ident, $err_context:expr) => {{ IdentityFile::from_file(identity.clone()) - .map_err(|_| eyre!("import {} from file error", $err_import))? + .map_err(|e| eyre!("import from file error: {}", e))? .with_callbacks(UiCallbacks) .$method() .map_err(|e| eyre!("{}", e))? @@ -68,11 +61,11 @@ impl MasterIdentity { .with_context(|| $err_context)? }}; } - let ident = create_entity!(into_identities, "identity", "into identity fail"); + let ident = create!(into_identities, "into identity fail"); - let recp = create_entity!(to_recipients, "recip", "into recip fail"); + let recip = create!(to_recipients, "into recip fail"); - return Ok(ParsedIdentity::from_exist(ident, recp)); + return Ok(ParsedIdentity::from_exist(ident, recip)); } } }