git.delta.rocks / jrsonnet / refs/commits / 71200382b2ad

difftreelog

source

crates/fleet-base/src/keys.rs2.0 KiBsourcehistory
1use std::str::FromStr as _;23use age::Recipient;4use anyhow::{Result, anyhow};5use futures::{StreamExt as _, TryStreamExt as _};6use itertools::Itertools as _;7use tracing::warn;89use crate::host::Config;1011impl Config {12	pub fn cached_key(&self, host: &str) -> Option<String> {13		let data = self.data();14		let key = data.hosts.get(host).map(|h| &h.encryption_key);15		if let Some(key) = key {16			if key.is_empty() {17				return None;18			}19		}20		key.cloned()21	}22	pub fn update_key(&self, host: &str, key: String) {23		let mut data = self.data_mut();24		let host = data.hosts.entry(host.to_string()).or_default();25		host.encryption_key = key.trim().to_string();26	}2728	pub async fn key(&self, host: &str) -> anyhow::Result<String> {29		if let Some(key) = self.cached_key(host) {30			Ok(key)31		} else {32			warn!("Loading key for {}", host);33			let host = self.host(host).await?;34			let mut cmd = host.cmd("cat").await?;35			cmd.arg("/etc/ssh/ssh_host_ed25519_key.pub");36			let key = cmd.run_string().await?;37			self.update_key(&host.name, key.clone());38			Ok(key)39		}40	}41	/// Insecure, requires root42	pub async fn recipient(&self, host: &str) -> anyhow::Result<impl Recipient + use<>> {43		let key = self.key(host).await?;44		age::ssh::Recipient::from_str(&key).map_err(|e| anyhow!("parse recipient error: {:?}", e))45	}4647	pub async fn recipients(&self, hosts: Vec<String>) -> Result<Vec<impl Recipient + use<>>> {48		let hosts = self.expand_owner_set(hosts).await?;49		futures::stream::iter(hosts.iter())50			.then(|m| self.recipient(m.as_ref()))51			.try_collect::<Vec<_>>()52			.await53	}5455	#[allow(dead_code)]56	pub async fn orphaned_data(&self) -> Result<Vec<String>> {57		let mut out = Vec::new();58		let host_names = self59			.list_hosts()60			.await?61			.into_iter()62			.map(|h| h.name)63			.collect_vec();64		for hostname in self65			.data()66			.hosts67			.iter()68			.filter(|(_, host)| !host.encryption_key.is_empty())69			.map(|(n, _)| n)70		{71			if !host_names.contains(hostname) {72				out.push(hostname.to_owned())73			}74		}7576		Ok(out)77	}78}