git.delta.rocks / jrsonnet / refs/commits / 5fd92ba91a91

difftreelog

feat non-shared secrets

Yaroslav Bolyukin2021-10-01parent: #076f1fe.patch.diff
in: trunk

2 files changed

modifiedcmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth
before · cmds/fleet/src/cmds/secrets/mod.rs
1use crate::{fleetdata::FleetSecret, host::Config};2use anyhow::{bail, Result};3use std::io::{self, Cursor, Read};4use structopt::StructOpt;56#[derive(StructOpt)]7pub enum Secrets {8	/// Force load keys for all defined hosts9	ForceKeys,10	/// Add secret, data should be provided in stdin11	Add {12		/// Secret name13		name: String,14		/// Secret owners15		machines: Vec<String>,16		/// Override secret if already present17		#[structopt(long)]18		force: bool,19		#[structopt(long)]20		public: Option<String>,21	},22}2324impl Secrets {25	pub fn run(self, config: &Config) -> Result<()> {26		match self {27			Secrets::ForceKeys => {28				for host in config.list_hosts()? {29					if config.should_skip(&host) {30						continue;31					}32					config.key(&host)?;33				}34			}35			Secrets::Add {36				machines,37				name,38				force,39				public,40			} => {41				let recipients = machines42					.iter()43					.map(|m| config.recipient(m))44					.collect::<Result<Vec<_>>>()?;4546				let secret = {47					let mut input = vec![];48					io::stdin().read_to_end(&mut input)?;4950					let mut encrypted = vec![];51					let recipients = recipients52						.iter()53						.cloned()54						.map(|r| Box::new(r) as Box<dyn age::Recipient>)55						.collect();56					let mut encryptor =57						age::Encryptor::with_recipients(recipients).wrap_output(&mut encrypted)?;58					io::copy(&mut Cursor::new(input), &mut encryptor)?;59					encryptor.finish()?;60					encrypted61				};6263				let mut data = config.data_mut();64				if data.secrets.contains_key(&name) && !force {65					bail!("secret already defined");66				}67				data.secrets.insert(68					name,69					FleetSecret {70						owners: machines,71						expire_at: None,72						secret,73						public,74					},75				);76			}77		}78		Ok(())79	}80}
after · cmds/fleet/src/cmds/secrets/mod.rs
1use crate::{2	fleetdata::{FleetSecret, FleetSharedSecret},3	host::Config,4};5use anyhow::{bail, Result};6use std::{7	io::{self, Cursor, Read},8	path::PathBuf,9};10use structopt::StructOpt;1112#[derive(StructOpt)]13pub enum Secrets {14	/// Force load keys for all defined hosts15	ForceKeys,16	/// Add secret, data should be provided in stdin17	AddShared {18		/// Secret name19		name: String,20		/// Secret owners21		machines: Vec<String>,22		/// Override secret if already present23		#[structopt(long)]24		force: bool,25		#[structopt(long)]26		public: Option<String>,27		#[structopt(long)]28		public_file: Option<PathBuf>,29	},30	/// Add secret, data should be provided in stdin31	Add {32		/// Secret name33		name: String,34		/// Secret owners35		machine: String,36		/// Override secret if already present37		#[structopt(long)]38		force: bool,39		#[structopt(long)]40		public: Option<String>,41		#[structopt(long)]42		public_file: Option<PathBuf>,43	},44}4546impl Secrets {47	pub fn run(self, config: &Config) -> Result<()> {48		match self {49			Secrets::ForceKeys => {50				for host in config.list_hosts()? {51					if config.should_skip(&host) {52						continue;53					}54					config.key(&host)?;55				}56			}57			Secrets::AddShared {58				machines,59				name,60				force,61				public,62				public_file,63			} => {64				let recipients = machines65					.iter()66					.map(|m| config.recipient(m))67					.collect::<Result<Vec<_>>>()?;6869				let secret = {70					let mut input = vec![];71					io::stdin().read_to_end(&mut input)?;7273					let mut encrypted = vec![];74					let recipients = recipients75						.iter()76						.cloned()77						.map(|r| Box::new(r) as Box<dyn age::Recipient>)78						.collect();79					let mut encryptor =80						age::Encryptor::with_recipients(recipients).wrap_output(&mut encrypted)?;81					io::copy(&mut Cursor::new(input), &mut encryptor)?;82					encryptor.finish()?;83					encrypted84				};8586				let mut data = config.data_mut();87				if data.shared_secrets.contains_key(&name) && !force {88					bail!("secret already defined");89				}90				data.shared_secrets.insert(91					name,92					FleetSharedSecret {93						owners: machines,94						secret: FleetSecret {95							expire_at: None,96							secret,97							public: match (public, public_file) {98								(Some(v), None) => Some(v),99								(None, Some(v)) => Some(std::fs::read_to_string(&v)?),100								(Some(_), Some(_)) => {101									bail!("only public or public_file should be set")102								}103								(None, None) => None,104							},105						},106					},107				);108			}109			Secrets::Add {110				machine,111				name,112				force,113				public,114				public_file,115			} => {116				let recipient = config.recipient(&machine)?;117118				let secret = {119					let mut input = vec![];120					io::stdin().read_to_end(&mut input)?;121122					let mut encrypted = vec![];123					let recipient = Box::new(recipient) as Box<dyn age::Recipient>;124					let mut encryptor = age::Encryptor::with_recipients(vec![recipient])125						.wrap_output(&mut encrypted)?;126					io::copy(&mut Cursor::new(input), &mut encryptor)?;127					encryptor.finish()?;128					encrypted129				};130131				let mut data = config.data_mut();132				let host_secrets = data.host_secrets.entry(machine).or_default();133				if host_secrets.contains_key(&name) && !force {134					bail!("secret already defined");135				}136				host_secrets.insert(137					name,138					FleetSecret {139						expire_at: None,140						secret,141						public: match (public, public_file) {142							(Some(v), None) => Some(v),143							(None, Some(v)) => Some(std::fs::read_to_string(&v)?),144							(Some(_), Some(_)) => bail!("only public or public_file should be set"),145							(None, None) => None,146						},147					},148				);149			}150		}151		Ok(())152	}153}
modifiedcmds/fleet/src/fleetdata.rsdiffbeforeafterboth
--- a/cmds/fleet/src/fleetdata.rs
+++ b/cmds/fleet/src/fleetdata.rs
@@ -11,18 +11,29 @@
 }
 
 #[derive(Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
 pub struct FleetData {
 	#[serde(default)]
 	pub hosts: BTreeMap<String, HostData>,
 	#[serde(default)]
 	#[serde(skip_serializing_if = "BTreeMap::is_empty")]
-	pub secrets: BTreeMap<String, FleetSecret>,
+	pub shared_secrets: BTreeMap<String, FleetSharedSecret>,
+	#[serde(default)]
+	#[serde(skip_serializing_if = "BTreeMap::is_empty")]
+	pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,
 }
 
 #[derive(Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-pub struct FleetSecret {
+pub struct FleetSharedSecret {
 	pub owners: Vec<String>,
+	#[serde(flatten)]
+	pub secret: FleetSecret,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct FleetSecret {
 	#[serde(default)]
 	#[serde(skip_serializing_if = "Option::is_none")]
 	pub expire_at: Option<DateTime<Utc>>,