difftreelog
feat non-shared secrets
in: trunk
2 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
@@ -1,6 +1,12 @@
-use crate::{fleetdata::FleetSecret, host::Config};
+use crate::{
+ fleetdata::{FleetSecret, FleetSharedSecret},
+ host::Config,
+};
use anyhow::{bail, Result};
-use std::io::{self, Cursor, Read};
+use std::{
+ io::{self, Cursor, Read},
+ path::PathBuf,
+};
use structopt::StructOpt;
#[derive(StructOpt)]
@@ -8,7 +14,7 @@
/// Force load keys for all defined hosts
ForceKeys,
/// Add secret, data should be provided in stdin
- Add {
+ AddShared {
/// Secret name
name: String,
/// Secret owners
@@ -18,7 +24,23 @@
force: bool,
#[structopt(long)]
public: Option<String>,
+ #[structopt(long)]
+ public_file: Option<PathBuf>,
},
+ /// Add secret, data should be provided in stdin
+ Add {
+ /// Secret name
+ name: String,
+ /// Secret owners
+ machine: String,
+ /// Override secret if already present
+ #[structopt(long)]
+ force: bool,
+ #[structopt(long)]
+ public: Option<String>,
+ #[structopt(long)]
+ public_file: Option<PathBuf>,
+ },
}
impl Secrets {
@@ -32,11 +54,12 @@
config.key(&host)?;
}
}
- Secrets::Add {
+ Secrets::AddShared {
machines,
name,
force,
public,
+ public_file,
} => {
let recipients = machines
.iter()
@@ -61,16 +84,66 @@
};
let mut data = config.data_mut();
- if data.secrets.contains_key(&name) && !force {
+ if data.shared_secrets.contains_key(&name) && !force {
bail!("secret already defined");
}
- data.secrets.insert(
+ data.shared_secrets.insert(
name,
- FleetSecret {
+ FleetSharedSecret {
owners: machines,
+ secret: FleetSecret {
+ expire_at: None,
+ secret,
+ public: match (public, public_file) {
+ (Some(v), None) => Some(v),
+ (None, Some(v)) => Some(std::fs::read_to_string(&v)?),
+ (Some(_), Some(_)) => {
+ bail!("only public or public_file should be set")
+ }
+ (None, None) => None,
+ },
+ },
+ },
+ );
+ }
+ Secrets::Add {
+ machine,
+ name,
+ force,
+ public,
+ public_file,
+ } => {
+ let recipient = config.recipient(&machine)?;
+
+ let secret = {
+ let mut input = vec![];
+ io::stdin().read_to_end(&mut input)?;
+
+ let mut encrypted = vec![];
+ let recipient = Box::new(recipient) as Box<dyn age::Recipient>;
+ let mut encryptor = age::Encryptor::with_recipients(vec![recipient])
+ .wrap_output(&mut encrypted)?;
+ io::copy(&mut Cursor::new(input), &mut encryptor)?;
+ encryptor.finish()?;
+ encrypted
+ };
+
+ let mut data = config.data_mut();
+ let host_secrets = data.host_secrets.entry(machine).or_default();
+ if host_secrets.contains_key(&name) && !force {
+ bail!("secret already defined");
+ }
+ host_secrets.insert(
+ name,
+ FleetSecret {
expire_at: None,
secret,
- public,
+ public: match (public, public_file) {
+ (Some(v), None) => Some(v),
+ (None, Some(v)) => Some(std::fs::read_to_string(&v)?),
+ (Some(_), Some(_)) => bail!("only public or public_file should be set"),
+ (None, None) => None,
+ },
},
);
}
cmds/fleet/src/fleetdata.rsdiffbeforeafterboth11}11}121213#[derive(Serialize, Deserialize)]13#[derive(Serialize, Deserialize)]14#[serde(rename_all = "camelCase")]14pub struct FleetData {15pub struct FleetData {15 #[serde(default)]16 #[serde(default)]16 pub hosts: BTreeMap<String, HostData>,17 pub hosts: BTreeMap<String, HostData>,18 #[serde(default)]19 #[serde(skip_serializing_if = "BTreeMap::is_empty")]20 pub shared_secrets: BTreeMap<String, FleetSharedSecret>,17 #[serde(default)]21 #[serde(default)]18 #[serde(skip_serializing_if = "BTreeMap::is_empty")]22 #[serde(skip_serializing_if = "BTreeMap::is_empty")]19 pub secrets: BTreeMap<String, FleetSecret>,23 pub host_secrets: BTreeMap<String, BTreeMap<String, FleetSecret>>,20}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}213322#[derive(Serialize, Deserialize)]34#[derive(Serialize, Deserialize)]23#[serde(rename_all = "camelCase")]35#[serde(rename_all = "camelCase")]24pub struct FleetSecret {36pub struct FleetSecret {25 pub owners: Vec<String>,26 #[serde(default)]37 #[serde(default)]27 #[serde(skip_serializing_if = "Option::is_none")]38 #[serde(skip_serializing_if = "Option::is_none")]28 pub expire_at: Option<DateTime<Utc>>,39 pub expire_at: Option<DateTime<Utc>>,