difftreelog
feat support secrets without secret data
in: trunk
4 files changed
cmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -70,17 +70,21 @@
let mut input = vec![];
io::stdin().read_to_end(&mut input)?;
- let mut encrypted = vec![];
- let recipients = recipients
- .iter()
- .cloned()
- .map(|r| Box::new(r) as Box<dyn age::Recipient>)
- .collect();
- let mut encryptor =
- age::Encryptor::with_recipients(recipients).wrap_output(&mut encrypted)?;
- io::copy(&mut Cursor::new(input), &mut encryptor)?;
- encryptor.finish()?;
- encrypted
+ if input.is_empty() {
+ input
+ } else {
+ let mut encrypted = vec![];
+ let recipients = recipients
+ .iter()
+ .cloned()
+ .map(|r| Box::new(r) as Box<dyn age::Recipient>)
+ .collect();
+ let mut encryptor = age::Encryptor::with_recipients(recipients)
+ .wrap_output(&mut encrypted)?;
+ io::copy(&mut Cursor::new(input), &mut encryptor)?;
+ encryptor.finish()?;
+ encrypted
+ }
};
let mut data = config.data_mut();
cmds/fleet/src/fleetdata.rsdiffbeforeafterboth1use chrono::{DateTime, Utc};2use serde::{Deserialize, Deserializer, Serialize, Serializer};3use std::collections::BTreeMap;45#[derive(Serialize, Deserialize, Default)]6#[serde(rename_all = "camelCase")]7pub struct HostData {8 #[serde(default)]9 #[serde(skip_serializing_if = "String::is_empty")]10 pub encryption_key: String,11}1213#[derive(Serialize, Deserialize)]14#[serde(rename_all = "camelCase")]15pub struct FleetData {16 #[serde(default)]17 pub hosts: BTreeMap<String, HostData>,18 #[serde(default)]19 #[serde(skip_serializing_if = "BTreeMap::is_empty")]20 pub shared_secrets: BTreeMap<String, FleetSharedSecret>,21 #[serde(default)]22 #[serde(skip_serializing_if = "BTreeMap::is_empty")]23 pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,24}2526#[derive(Serialize, Deserialize)]27#[serde(rename_all = "camelCase")]28pub struct FleetSharedSecret {29 pub owners: Vec<String>,30 #[serde(flatten)]31 pub secret: FleetSecret,32}3334#[derive(Serialize, Deserialize)]35#[serde(rename_all = "camelCase")]36pub struct FleetSecret {37 #[serde(default)]38 #[serde(skip_serializing_if = "Option::is_none")]39 pub expire_at: Option<DateTime<Utc>>,40 #[serde(skip_serializing_if = "Option::is_none")]41 pub public: Option<String>,42 #[serde(serialize_with = "as_z85", deserialize_with = "from_z85")]43 pub secret: Vec<u8>,44}4546fn as_z85<S>(key: &[u8], serializer: S) -> Result<S::Ok, S::Error>47where48 S: Serializer,49{50 serializer.serialize_str(&z85::encode(&key))51}5253fn from_z85<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>54where55 D: Deserializer<'de>,56{57 use serde::de::Error;58 String::deserialize(deserializer)59 .and_then(|string| z85::decode(&string).map_err(|err| Error::custom(err.to_string())))60}1use chrono::{DateTime, Utc};2use serde::{Deserialize, Deserializer, Serialize, Serializer};3use std::collections::BTreeMap;45#[derive(Serialize, Deserialize, Default)]6#[serde(rename_all = "camelCase")]7pub struct HostData {8 #[serde(default)]9 #[serde(skip_serializing_if = "String::is_empty")]10 pub encryption_key: String,11}1213#[derive(Serialize, Deserialize)]14#[serde(rename_all = "camelCase")]15pub struct FleetData {16 #[serde(default)]17 pub hosts: BTreeMap<String, HostData>,18 #[serde(default)]19 #[serde(skip_serializing_if = "BTreeMap::is_empty")]20 pub shared_secrets: BTreeMap<String, FleetSharedSecret>,21 #[serde(default)]22 #[serde(skip_serializing_if = "BTreeMap::is_empty")]23 pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,24}2526#[derive(Serialize, Deserialize)]27#[serde(rename_all = "camelCase")]28pub struct FleetSharedSecret {29 pub owners: Vec<String>,30 #[serde(flatten)]31 pub secret: FleetSecret,32}3334#[derive(Serialize, Deserialize)]35#[serde(rename_all = "camelCase")]36pub struct FleetSecret {37 #[serde(default)]38 #[serde(skip_serializing_if = "Option::is_none")]39 pub expire_at: Option<DateTime<Utc>>,40 #[serde(skip_serializing_if = "Option::is_none")]41 pub public: Option<String>,42 #[serde(43 default,44 skip_serializing_if = "Vec::is_empty",45 serialize_with = "as_z85",46 deserialize_with = "from_z85"47 )]48 pub secret: Vec<u8>,49}5051fn as_z85<S>(key: &[u8], serializer: S) -> Result<S::Ok, S::Error>52where53 S: Serializer,54{55 serializer.serialize_str(&z85::encode(&key))56}5758fn from_z85<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>59where60 D: Deserializer<'de>,61{62 use serde::de::Error;63 String::deserialize(deserializer)64 .and_then(|string| z85::decode(&string).map_err(|err| Error::custom(err.to_string())))65}cmds/install-secrets/src/main.rsdiffbeforeafterboth--- a/cmds/install-secrets/src/main.rs
+++ b/cmds/install-secrets/src/main.rs
@@ -29,16 +29,21 @@
mode: String,
owner: String,
#[serde(deserialize_with = "from_z85")]
- secret: Vec<u8>,
+ secret: Option<Vec<u8>>,
}
-fn from_z85<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
+fn from_z85<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
- String::deserialize(deserializer)
- .and_then(|string| z85::decode(&string).map_err(|err| Error::custom(err.to_string())))
+ if let Some(v) = <Option<String>>::deserialize(deserializer)? {
+ Ok(Some(
+ z85::decode(&v).map_err(|err| Error::custom(err.to_string()))?,
+ ))
+ } else {
+ Ok(None)
+ }
}
type Data = HashMap<String, DataItem>;
@@ -49,6 +54,11 @@
name: &str,
value: DataItem,
) -> Result<()> {
+ if value.secret.is_none() {
+ return Ok(());
+ }
+ let secret = value.secret.as_ref().unwrap();
+
let mut path = dir.to_path_buf();
path.push(name);
if path.strip_prefix(&dir).is_err() {
@@ -88,7 +98,7 @@
// File is owned by root, and only root can modify it
let decrypted = {
- let mut input = Cursor::new(&value.secret);
+ let mut input = Cursor::new(&secret);
let decryptor = Decryptor::new(&mut input).context("failed to init decryptor")?;
let decryptor = match decryptor {
Decryptor::Recipients(r) => r,
modules/nixos/secrets.nixdiffbeforeafterboth--- a/modules/nixos/secrets.nix
+++ b/modules/nixos/secrets.nix
@@ -3,7 +3,9 @@
sysConfig = config;
secretType = types.submodule ({ config, ... }: {
config = {
- path = mkOptionDefault "/run/secrets/${config._module.args.name}";
+ path = mkOptionDefault (if config.secret == null then (error "secret is not set") else "/run/secrets/${config._module.args.name}");
+ publicPath = mkOptionDefault (pkgs.writeText "pub-${config._module.args.name}" config.public);
+ secret = mkIf (config.public != null) "";
};
options = {
public = mkOption {
@@ -12,7 +14,7 @@
default = null;
};
secret = mkOption {
- type = types.str;
+ type = types.nullOr types.str;
description = "Encrypted secret data";
};
mode = mkOption {
@@ -36,6 +38,11 @@
readOnly = true;
description = "Path to the decrypted secret";
};
+ publicPath = mkOption {
+ type = types.package;
+ readOnly = true;
+ description = "Path to the public part of secret";
+ };
};
});
secretsFile = pkgs.writeTextFile {