difftreelog
feat use builtin for getting secret
in: trunk
12 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -723,15 +723,6 @@
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
-name = "convert_case"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
name = "cookie-factory"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -765,34 +756,6 @@
]
[[package]]
-name = "crossterm"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
-dependencies = [
- "bitflags",
- "crossterm_winapi",
- "derive_more",
- "document-features",
- "filedescriptor",
- "mio",
- "parking_lot",
- "rustix 1.1.2",
- "signal-hook",
- "signal-hook-mio",
- "winapi",
-]
-
-[[package]]
-name = "crossterm_winapi"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
-dependencies = [
- "winapi",
-]
-
-[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -932,27 +895,6 @@
dependencies = [
"powerfmt",
"serde_core",
-]
-
-[[package]]
-name = "derive_more"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
-dependencies = [
- "derive_more-impl",
-]
-
-[[package]]
-name = "derive_more-impl"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "syn",
]
[[package]]
@@ -976,15 +918,6 @@
"proc-macro2",
"quote",
"syn",
-]
-
-[[package]]
-name = "document-features"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
-dependencies = [
- "litrs",
]
[[package]]
@@ -1073,17 +1006,6 @@
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
-name = "filedescriptor"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d"
-dependencies = [
- "libc",
- "thiserror 1.0.69",
- "winapi",
-]
-
-[[package]]
name = "find-crate"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1128,7 +1050,6 @@
"chrono",
"clap",
"clap_complete",
- "crossterm",
"fleet-base",
"fleet-shared",
"futures",
@@ -1142,7 +1063,6 @@
"openssh",
"opentelemetry",
"opentelemetry_sdk",
- "owo-colors",
"peg",
"regex",
"serde",
@@ -1503,12 +1423,6 @@
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
-name = "hermit-abi"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
-
-[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1961,24 +1875,7 @@
dependencies = [
"memchr",
"serde",
-]
-
-[[package]]
-name = "is-terminal"
-version = "0.4.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.59.0",
]
-
-[[package]]
-name = "is_ci"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
[[package]]
name = "is_terminal_polyfill"
@@ -2083,12 +1980,6 @@
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
-
-[[package]]
-name = "litrs"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
@@ -2161,7 +2052,6 @@
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
- "log",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.59.0",
]
@@ -2428,16 +2318,6 @@
]
[[package]]
-name = "owo-colors"
-version = "4.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
-dependencies = [
- "supports-color 2.1.0",
- "supports-color 3.0.2",
-]
-
-[[package]]
name = "papergrid"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3335,27 +3215,6 @@
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
-[[package]]
-name = "signal-hook"
-version = "0.3.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[package]]
-name = "signal-hook-mio"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
-dependencies = [
- "libc",
- "mio",
- "signal-hook",
-]
[[package]]
name = "signal-hook-registry"
@@ -3449,25 +3308,6 @@
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
-name = "supports-color"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
-dependencies = [
- "is-terminal",
- "is_ci",
-]
-
-[[package]]
-name = "supports-color"
-version = "3.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6"
-dependencies = [
- "is_ci",
-]
-
-[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4170,12 +4010,6 @@
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
-name = "unicode-segmentation"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
-
-[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4448,25 +4282,9 @@
"home",
"once_cell",
"rustix 0.38.44",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
]
[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4474,12 +4292,6 @@
dependencies = [
"windows-sys 0.61.2",
]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
README.adocdiffbeforeafterboth--- a/README.adoc
+++ b/README.adoc
@@ -211,7 +211,7 @@
];
# And finally, I have secrets, which are shared between machines.
# Note that this example is somewhat wrong, as this goes not into the machine configuration, but to fleet configuration.
- sharedSecrets = {
+ secrets = {
"ca.pem" = {
# This is just the public key, no need to regenerate it to change owner list
regenerateOnOwnerAdded = false;
cmds/fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -28,12 +28,10 @@
async-trait = "0.1"
base64 = "0.22.1"
chrono = { version = "0.4", features = ["serde"] }
-crossterm = { version = "0.29.0", features = ["use-dev-tty"] }
futures = "0.3"
hostname = "0.4.1"
itertools = "0.14"
openssh = "0.11"
-owo-colors = { version = "4.2", features = ["supports-color", "supports-colors"] }
peg = "0.8"
regex = "1.11"
shlex = "1.3"
cmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth11 fleetdata::{FleetSecretData, FleetSecretDistribution, FleetSecretPart, encrypt_secret_data},11 fleetdata::{FleetSecretData, FleetSecretDistribution, FleetSecretPart, encrypt_secret_data},12 host::Config,12 host::Config,13 opts::FleetOpts,13 opts::FleetOpts,14 secret::{Expectations, RegenerationReason, SharedSecretDefinition, secret_needs_regeneration},14 secret::{Expectations, RegenerationReason, secret_needs_regeneration},15};15};16use fleet_shared::SecretData;16use fleet_shared::SecretData;17use nix_eval::{NixType, Value, nix_go, nix_go_json};17use nix_eval::{NixType, Value, nix_go, nix_go_json};18use owo_colors::OwoColorize;19use serde::Deserialize;18use serde::Deserialize;20use tabled::{Table, Tabled};19use tabled::{Table, Tabled};21use tokio::{fs::read, task::spawn_blocking};20use tokio::{fs::read, task::spawn_blocking};69 },68 },70}69}717072#[allow(clippy::too_many_arguments)]71/*73#[tracing::instrument(skip(config, secret, definition, prefer_identities))]72#[allow(clippy::too_many_arguments)]74async fn maybe_regenerate_shared_secret(73#[tracing::instrument(skip(config, secret, definition, prefer_identities))]75 secret_name: &str,74async fn maybe_regenerate_shared_secret(76 config: &Config,75 secret_name: &str,77 mut secret: FleetSecretDistribution,76 config: &Config,78 definition: SharedSecretDefinition,77 mut secret: FleetSecretDistribution,79 prefer_identities: &[String],78 definition: SharedSecretDefinition,80 expectations: &Expectations,79 prefer_identities: &[String],81) -> Result<FleetSecretDistribution> {80 expectations: &Expectations,82 let reason = secret_needs_regeneration(&secret.secret, &secret.owners, expectations);81) -> Result<FleetSecretDistribution> {83 let value = definition.definition_value();82 let reason = secret_needs_regeneration(&secret.secret, &secret.owners, expectations);8483 let value = definition.definition_value();85 let (should_reencrypt, reason) = match reason {8486 Some(RegenerationReason::OwnersAdded(_)) => {85 let (should_reencrypt, reason) = match reason {87 // Secret always needs to be reencrypted for new owners to be able to read it86 Some(RegenerationReason::OwnersAdded(_)) => {88 (87 // Secret always needs to be reencrypted for new owners to be able to read it89 true,88 (90 if nix_go_json!(value.regenerateOnOwnerAdded) {89 true,91 reason90 if nix_go_json!(value.regenerateOnOwnerAdded) {92 } else {91 reason93 None92 } else {94 },93 None95 )94 },96 }95 )97 Some(RegenerationReason::OwnersRemoved(_)) => {96 }98 // No need to reencrypt, we can just leave stanzas in place.97 Some(RegenerationReason::OwnersRemoved(_)) => {99 if nix_go_json!(value.regenerateOnOwnerRemoved) {98 // No need to reencrypt, we can just leave stanzas in place.100 (true, reason)99 if nix_go_json!(value.regenerateOnOwnerRemoved) {101 } else {100 (true, reason)102 (false, None)101 } else {103 }102 (false, None)104 }103 }105 Some(_) => (true, reason),104 }106 None => (false, None),105 Some(_) => (true, reason),107 };106 None => (false, None),108107 };109 if let Some(reason) = reason {108110 info!("secret needs to be regenerated: {reason}");109 if let Some(reason) = reason {111 let generated = generate_shared(config, secret_name, definition, expectations).await?;110 info!("secret needs to be regenerated: {reason}");112 Ok(generated)111 let generated = generate_shared(config, secret_name, definition, expectations).await?;113 } else if should_reencrypt {112 Ok(generated)114 info!("secret needs to be reencrypted");113 } else if should_reencrypt {115 let identity_holder = if !prefer_identities.is_empty() {114 info!("secret needs to be reencrypted");116 prefer_identities115 let identity_holder = if !prefer_identities.is_empty() {117 .iter()116 prefer_identities118 .find(|i| secret.owners.iter().any(|s| s == *i))117 .iter()119 } else {118 .find(|i| secret.owners.iter().any(|s| s == *i))120 secret.owners.first()119 } else {121 };120 secret.owners.first()122 let Some(identity_holder) = identity_holder else {121 };123 bail!("no available holder found");122 let Some(identity_holder) = identity_holder else {124 };123 bail!("no available holder found");125124 };126 for (part_name, part) in secret.secret.parts.iter_mut() {125127 let _span = info_span!("part reencryption", part_name);126 for (part_name, part) in secret.secret.parts.iter_mut() {128 if !part.raw.encrypted {127 let _span = info_span!("part reencryption", part_name);129 continue;128 if !part.raw.encrypted {130 }129 continue;131 let host = config.host(identity_holder).await?;130 }132 let encrypted = host131 let host = config.host(identity_holder).await?;133 .reencrypt(132 let encrypted = host134 part.raw.clone(),133 .reencrypt(135 expectations.owners.iter().cloned().collect(),134 part.raw.clone(),136 )135 expectations.owners.iter().cloned().collect(),137 .await?;136 )138 part.raw = encrypted;137 .await?;139 }138 part.raw = encrypted;140 secret.owners = expectations.owners.clone();139 }141 Ok(secret)140 secret.owners = expectations.owners.clone();142 } else {141 Ok(secret)143 Ok(secret)142 } else {144 }143 Ok(secret)145}144 }145}146*/146147147#[derive(Deserialize)]148#[derive(Deserialize)]148#[serde(rename_all = "camelCase")]149#[serde(rename_all = "camelCase")]314 }315 }315 }316 }316}317}317async fn generate_shared(318/*318 config: &Config,319async fn generate_shared(319 display_name: &str,320 config: &Config,320 secret: SharedSecretDefinition,321 display_name: &str,321 expectations: &Expectations,322 secret: SharedSecretDefinition,322) -> Result<FleetSecretDistribution> {323 expectations: &Expectations,323 // let owners: Vec<String> = nix_go_json!(secret.expectedOwners);324) -> Result<FleetSecretDistribution> {324 Ok(FleetSecretDistribution {325 // let owners: Vec<String> = nix_go_json!(secret.expectedOwners);325 managed: Some(true),326 Ok(FleetSecretDistribution {326 secret: generate(327 managed: Some(true),327 config,328 secret: generate(328 display_name,329 config,329 secret.definition_value(),330 display_name,330 expectations,331 secret.definition_value(),331 )332 expectations,332 .await?,333 )333 owners: expectations.owners.clone(),334 .await?,334 })335 owners: expectations.owners.clone(),335}336 })337}*/336338337async fn parse_public(339async fn parse_public(338 public: Option<String>,340 public: Option<String>,625 #[tabled(rename = "Owners")]627 #[tabled(rename = "Owners")]626 owners: String,628 owners: String,627 }629 }628 let mut table = vec![];630 // let mut table = vec![];629 for name in configured.iter().cloned() {631 for name in configured.iter().cloned() {630 let config = config.clone();632 let config = config.clone();631 let data = config.shared_secret(&name).expect("exists");633 let data = config.shared_secret(&name).expect("exists");632 let definition = config.shared_secret_definition(&name)?;634 /*633 let expectations = definition.expectations()?;635 let definition = config.shared_secret_definition(&name)?;634 let owners = data636 let expectations = definition.expectations()?;635 .owners()637 let owners = data636 .map(|o| {638 .owners()637 if expectations.owners.contains(o) {639 .map(|o| {638 o.green().to_string()640 if expectations.owners.contains(o) {639 } else {641 o.green().to_string()640 o.red().to_string()642 } else {641 }643 o.red().to_string()642 })644 }643 .collect::<Vec<_>>();645 })644 table.push(SecretDisplay {646 .collect::<Vec<_>>();645 owners: owners.join(", "),647 table.push(SecretDisplay {646 name,648 owners: owners.join(", "),647 })649 name,650 })651*/648 }652 }649 info!("loaded\n{}", Table::new(table).to_string())653 // info!("loaded\n{}", Table::new(table).to_string())650 }654 }651 Secret::Edit {655 Secret::Edit {652 name,656 name,crates/fleet-base/src/host.rsdiffbeforeafterboth--- a/crates/fleet-base/src/host.rs
+++ b/crates/fleet-base/src/host.rs
@@ -23,7 +23,6 @@
use crate::{
command::MyCommand,
fleetdata::{FleetData, FleetSecretData, FleetSecretDistribution, FleetSecretDistributions},
- secret::{HostSecretDefinition, SharedSecretDefinition},
};
pub struct FleetConfigInternals {
@@ -31,7 +30,7 @@
pub directory: PathBuf,
/// builtins.currentSystem
pub local_system: String,
- pub data: Mutex<FleetData>,
+ pub data: Arc<Mutex<FleetData>>,
pub nix_args: Vec<OsString>,
/// fleet_config.config
pub config_field: Value,
@@ -520,13 +519,6 @@
let nixos = self.nixos_unchecked_config()?;
let secrets = nix_go!(nixos.secrets);
secrets.list_fields()
- }
- pub fn secret_definition(&self, name: &str) -> Result<HostSecretDefinition> {
- let nixos = self.nixos_unchecked_config()?;
- Ok(HostSecretDefinition(
- self.name.clone(),
- nix_go!(nixos.secrets[{ name }]),
- ))
}
/// Packages for this host, resolved with nixpkgs overlays
@@ -665,12 +657,6 @@
pub fn shared_secret(&self, secret: &str) -> Option<FleetSecretDistributions> {
let data = self.data();
data.secrets.get(secret).cloned()
- }
- pub fn shared_secret_definition(&self, secret: &str) -> Result<SharedSecretDefinition> {
- let config_field = &self.config_field;
- Ok(SharedSecretDefinition(nix_go!(
- config_field.sharedSecrets[{ secret }]
- )))
}
// TODO: Should this be something modifiable from other processes?
crates/fleet-base/src/opts.rsdiffbeforeafterboth--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -211,7 +211,7 @@
}
let bytes =
std::fs::read_to_string(&fleet_data_path).context("reading fleet state (fleet.nix)")?;
- let data = Mutex::new(FleetData::from_str(&bytes)?);
+ let data = Arc::new(Mutex::new(FleetData::from_str(&bytes)?));
let mut fetch_settings = FetchSettings::new();
fetch_settings.set(c"warn-dirty", c"false");
@@ -239,8 +239,7 @@
let builtins_field = Value::eval("builtins")?;
let fleet_root = flake.get_field("fleetConfigurations")?;
- let data_val = Value::serialized(&data)?;
- let fleet_field = nix_go!(fleet_root.default(data_val));
+ let fleet_field = nix_go!(fleet_root.default(Obj {}));
let config_field = nix_go!(fleet_field.config);
crates/fleet-base/src/primops.rsdiffbeforeafterboth--- a/crates/fleet-base/src/primops.rs
+++ b/crates/fleet-base/src/primops.rs
@@ -1,4 +1,9 @@
-use nix_eval::NativeFn;
+use std::collections::HashMap;
+use std::sync::{Arc, Mutex};
+
+use nix_eval::{NativeFn, Value};
+
+use crate::fleetdata::{FleetData, FleetSecrets};
#[derive(thiserror::Error, Debug)]
enum Error {}
@@ -15,30 +20,32 @@
fn host_parts(&self, host: &str, name: &str) -> Parts;
}
-struct FsSecretsBackend {
+struct FsSecretsBackend {}
-}
-
-pub fn init_primops() {
+pub fn init_primops(secrets: Arc<Mutex<FleetData>>) {
NativeFn::new(
- c"fleet_ensure_secret",
+ c"fleet_ensure_host_secret",
c"Ensure secret existence for a host, regenerating it in case of some mismatch",
- [
- c"host",
- c"secret",
- c"expected_parts",
- c"expected_encrypted_parts",
- c"generator",
- ],
- |[
- host,
- secret,
- expected_parts,
- expected_encrypted_parts,
- generator,
- ]| {
-
- todo!()
+ [c"host", c"secret", c"generator"],
+ |[host, secret, generator]| {
+ todo!("ensure secret");
+ Ok(Value::new_attrs(HashMap::from_iter([(
+ "raw",
+ Value::new_str("rawData"),
+ )])))
+ },
+ )
+ .register();
+ NativeFn::new(
+ c"fleet_ensure_host_secret",
+ c"Ensure secret existence for a host, regenerating it in case of some mismatch",
+ [c"host", c"secret", c"generator"],
+ |[host, secret, generator]| {
+ todo!("ensure secret");
+ Ok(Value::new_attrs(HashMap::from_iter([(
+ "raw",
+ Value::new_str("rawData"),
+ )])))
},
)
.register();
crates/fleet-base/src/secret.rsdiffbeforeafterboth--- a/crates/fleet-base/src/secret.rs
+++ b/crates/fleet-base/src/secret.rs
@@ -1,8 +1,6 @@
use std::collections::BTreeSet;
-use anyhow::Result;
use chrono::{DateTime, Utc};
-use nix_eval::{Value, nix_go, nix_go_json};
use crate::fleetdata::FleetSecretData;
@@ -12,63 +10,6 @@
pub generation_data: serde_json::Value,
pub public_parts: BTreeSet<String>,
pub private_parts: BTreeSet<String>,
-}
-
-pub struct HostSecretDefinition(pub(crate) String, pub(crate) Value);
-impl HostSecretDefinition {
- pub fn is_managed(&self) -> Result<bool> {
- let def = self.definition_value()?;
- Ok(!nix_go!(def.generator).is_null())
- }
- pub fn is_shared(&self) -> Result<bool> {
- let def = self.definition_value()?;
- Ok(nix_go_json!(def.shared))
- }
- pub fn expectations(&self) -> Result<Expectations> {
- let def = self.definition_value()?;
- let parts = nix_go!(def.parts);
-
- let mut public_parts = BTreeSet::new();
- let mut private_parts = BTreeSet::new();
- for part in parts.list_fields()? {
- if nix_go_json!(parts[&part].encrypted) {
- private_parts.insert(part.clone());
- } else {
- public_parts.insert(part.clone());
- }
- }
-
- Ok(Expectations {
- owners: BTreeSet::from([self.0.clone()]),
- generation_data: nix_go_json!(def.expectedGenerationData),
- public_parts,
- private_parts,
- })
- }
- pub fn definition_value(&self) -> Result<Value> {
- let value = &self.1;
- Ok(nix_go!(value.definition))
- }
-}
-
-pub struct SharedSecretDefinition(pub(crate) Value);
-impl SharedSecretDefinition {
- pub fn is_managed(&self) -> Result<bool> {
- let value = &self.0;
- Ok(!nix_go!(value.generator).is_null())
- }
- pub fn expectations(&self) -> Result<Expectations> {
- let value = &self.0;
- Ok(Expectations {
- owners: nix_go_json!(value.expectedOwners),
- generation_data: nix_go_json!(value.expectedGenerationData),
- public_parts: nix_go_json!(value.expectedPublicParts),
- private_parts: nix_go_json!(value.expectedPrivateParts),
- })
- }
- pub fn definition_value(&self) -> Value {
- self.0.clone()
- }
}
#[derive(thiserror::Error, Debug)]
modules/module-list.nixdiffbeforeafterboth--- a/modules/module-list.nix
+++ b/modules/module-list.nix
@@ -6,5 +6,4 @@
./nixos.nix
./nixpkgs.nix
./secrets.nix
- ./secrets-data.nix
]
modules/nixos/secrets.nixdiffbeforeafterboth--- a/modules/nixos/secrets.nix
+++ b/modules/nixos/secrets.nix
@@ -8,50 +8,26 @@
let
inherit (builtins)
hashString
- elemAt
- length
toJSON
- filter
;
inherit (lib.stringsWithDeps) stringAfter;
inherit (lib.options) mkOption literalExpression;
inherit (lib.lists) optional;
- inherit (lib.attrsets) mapAttrs mapAttrsToList;
- inherit (lib.modules) mkIf mkMerge;
+ inherit (lib.attrsets) mapAttrs;
+ inherit (lib.modules) mkIf;
inherit (lib.types)
submodule
str
attrsOf
nullOr
unspecified
- lazyAttrsOf
uniq
functionTo
package
- listOf
- bool
;
inherit (fleetLib.strings) decodeRawSecret;
sysConfig = config;
- secretPartDataType = submodule {
- options = {
- raw = mkOption {
- type = str;
- internal = true;
- description = "Encoded & Encrypted secret part data, passed from fleet.nix";
- };
- };
- };
- secretDataType = submodule {
- freeformType = lazyAttrsOf secretPartDataType;
- options = {
- shared = mkOption {
- description = "Is this secret owned by this machine, or propagated from shared secrets";
- default = false;
- };
- };
- };
secretPartType =
secretName:
submodule (
@@ -61,11 +37,6 @@
in
{
options = {
- encrypted = mkOption {
- type = bool;
- description = "Is this secret part supposed to be encrypted?";
- };
-
hash = mkOption {
type = str;
description = "Hash of secret in encoded format";
@@ -82,17 +53,17 @@
type = str;
description = "Secret public data (only available for plaintext)";
};
+ raw = mkOption {
+ type = str;
+ description = "Raw (encoded/encrypted secret part data)";
+ };
+ };
+ config = {
+ hash = hashString "sha1" config.raw;
+ data = decodeRawSecret config.raw;
+ path = "/run/secrets/${secretName}/${config.hash}-${partName}";
+ stablePath = "/run/secrets/${secretName}/${partName}";
};
- config =
- let
- raw = sysConfig.data.secrets.${secretName}.${partName}.raw;
- in
- {
- hash = hashString "sha1" raw;
- data = decodeRawSecret raw;
- path = "/run/secrets/${secretName}/${config.hash}-${partName}";
- stablePath = "/run/secrets/${secretName}/${partName}";
- };
}
);
secretType = submodule (
@@ -105,14 +76,9 @@
in
{
options = {
- shared = mkOption {
- type = bool;
- description = "Was this secret propagated from a shared secret?";
- };
parts = mkOption {
- type = lazyAttrsOf (secretPartType secretName);
+ type = attrsOf (secretPartType secretName);
description = "Definition of secret parts";
- default = { };
};
generator = mkOption {
type = uniq (nullOr (functionTo package));
@@ -134,47 +100,14 @@
description = "Group of the secret";
default = sysConfig.users.users.${config.owner}.group;
defaultText = literalExpression "config.users.users.$${owner}.group";
- };
- expectedGenerationData = mkOption {
- type = unspecified;
- description = "Data that gets embedded into secret part";
- default = null;
};
};
config = {
- shared = (sysConfig.data.secrets.${secretName} or { shared = false; }).shared;
- parts = mkMerge [
- (mkIf (config.generator != null)
- (
- # Get fake derivation body, in future it should be implemented the same way as in Rust.
- lib.callPackageWith (
- pkgs
- // {
- mkSecretGenerator = pkgs.stdenv.mkDerivation;
- mkImpureSecretGenerator = pkgs.stdenv.mkDerivation;
- }
- ) config.generator { }
- ).parts
- )
- (mapAttrs (_: _: { }) (
- removeAttrs (sysConfig.data.secrets.${secretName} or { }) [
- "shared"
- "managed"
- ]
- ))
- ];
+ parts = builtins.fleet_ensure_host_secret sysConfig.networking.hostName secretName config.generator;
};
}
);
- processPart = secretName: partName: part: {
- inherit (part) path stablePath;
- raw = config.data.secrets.${secretName}.${partName}.raw;
- };
- processSecret = secretName: secret: {
- inherit (secret.definition) group mode owner;
- parts = (mapAttrs (processPart secretName) (secret.definition.parts));
- };
- secretsData = (mapAttrs (processSecret) config.secrets);
+ secretsData = (mapAttrs (_: s: s.definition) config.secrets);
secretsFile = pkgs.writeTextFile {
name = "secrets.json";
text = toJSON secretsData;
@@ -185,11 +118,6 @@
in
{
options = {
- data.secrets = mkOption {
- type = attrsOf secretDataType;
- default = { };
- description = "Host-local secret data";
- };
secrets = mkOption {
type = attrsOf secretType;
default = { };
modules/secrets-data.nixdiffbeforeafterboth--- a/modules/secrets-data.nix
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- lib,
- fleetLib,
- ...
-}:
-let
- inherit (fleetLib.options) mkDataOption;
- inherit (lib.options) mkOption;
- inherit (lib.types)
- nullOr
- listOf
- str
- attrsOf
- submodule
- bool
- unspecified
- ;
-
- secretDataValue = {
- options = {
- raw = mkOption {
- type = nullOr str;
- description = "Raw secret data in unspecified encoded and optionally encrypted format.";
- default = null;
- };
- };
- };
-
- sharedSecretData = {
- freeformType = attrsOf (submodule secretDataValue);
- options = {
- managed = mkOption {
- type = nullOr bool;
- description = "Is current fleet data value is generated by generator";
- default = null;
- };
-
- createdAt = mkOption {
- type = str;
- description = "Timestamp of secret generation/last rotation.";
- default = null;
- };
- expiresAt = mkOption {
- type = nullOr str;
- description = "Expiration timestamp triggering mandatory secret rotation.";
- default = null;
- };
-
- owners = mkOption {
- type = listOf str;
- description = ''
- List of hosts currently authorized to decrypt this shared secret.
-
- If owners differ from expected owners, the secret is considered outdated
- and requires regeneration or re-encryption.
- '';
- default = [ ];
- };
- generationData = mkOption {
- type = unspecified;
- description = "Contextual metadata associated with secret part.";
- default = null;
- };
- };
- };
-
- managerKey = {
- options = {
- name = mkOption {
- type = str;
- description = "Who does this manager key belongs to.";
- };
- key = mkOption {
- type = str;
- description = "Age-compatible key";
- };
- };
- config = { };
- };
-in
-{
- options.data = mkDataOption ({ config, ... }:
- {
- options = {
- managerKeys = mkOption {
- type = listOf (submodule managerKey);
- };
- secrets = mkOption {
- type = attrsOf (listOf submodule sharedSecretData);
- default = { };
- description = "Shared secret data.";
- };
- };
- });
-}
modules/secrets.nixdiffbeforeafterboth--- a/modules/secrets.nix
+++ b/modules/secrets.nix
@@ -5,7 +5,6 @@
let
inherit (lib.options) mkOption literalExpression;
inherit (lib.types)
- unspecified
nullOr
listOf
str
@@ -66,22 +65,7 @@
An input to this function - `pkgs` of a generator host with implementation-defined representation of extra encryption data,
use `mkSecretGenerator` helpers to implement own generators.
'';
- default = null;
- };
- expectedGenerationData = mkOption {
- type = unspecified;
- description = "Contextual metadata embedded within the secret part value";
default = null;
- };
- expectedPrivateParts = mkOption {
- type = listOf str;
- default = [ ];
- description = "List of parts that are expected to be encrypted";
- };
- expectedPublicParts = mkOption {
- type = listOf str;
- default = [ ];
- description = "List of parts that are expected to be public";
};
};
};