Remove openbao helper and replace it with more general program
This gets rid of the messy nix code for handling bitwarden secrets, and unifies it all into a nice single program in rust. Ensuring that only the needed secrets are loaded.
This commit is contained in:
parent
e6a152e95c
commit
8640dce7bc
31 changed files with 1159 additions and 958 deletions
105
rust/program/infrastructure/src/secrets/openbao.rs
Normal file
105
rust/program/infrastructure/src/secrets/openbao.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::{collections::BTreeMap, marker::PhantomData, vec::IntoIter};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::secrets::Endpoint;
|
||||
|
||||
pub struct EnvEntry<T>(Vec<(&'static str, String)>, PhantomData<T>);
|
||||
|
||||
impl<T: Endpoint> EnvEntry<T> {
|
||||
pub fn try_new_from_env() -> anyhow::Result<Self> {
|
||||
let mut result = Vec::with_capacity(T::ENV_KEYS.len());
|
||||
for key in T::ENV_KEYS {
|
||||
let value = common::env::read_env(key)?;
|
||||
result.push((*key, value));
|
||||
}
|
||||
Ok(Self(result, PhantomData))
|
||||
}
|
||||
|
||||
fn new_from_values(values: Vec<(&'static str, String)>) -> Self {
|
||||
Self(values, PhantomData)
|
||||
}
|
||||
|
||||
pub fn read_from_bao() -> anyhow::Result<Self> {
|
||||
read_bao_data::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<EnvEntry<T>> for Vec<(&'static str, String)> {
|
||||
fn from(value: EnvEntry<T>) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for EnvEntry<T> {
|
||||
type Item = (&'static str, String);
|
||||
|
||||
type IntoIter = IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T: Endpoint> serde::Deserialize<'de> for EnvEntry<T> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(EnvEntryVisitor(PhantomData))
|
||||
}
|
||||
}
|
||||
struct EnvEntryVisitor<T>(PhantomData<T>);
|
||||
|
||||
impl<'de, T: Endpoint> serde::de::Visitor<'de> for EnvEntryVisitor<T> {
|
||||
type Value = EnvEntry<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_fmt(format_args!(
|
||||
"a map with unique keys {} with string values",
|
||||
T::ENV_KEYS.join(", "),
|
||||
))
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut values = BTreeMap::<&'static str, String>::new();
|
||||
while let Some((key, value)) = map.next_entry::<&'de str, String>()? {
|
||||
let mapped_key = T::ENV_KEYS.iter().find(|n| **n == key).copied();
|
||||
let Some(key) = mapped_key else {
|
||||
return Err(serde::de::Error::unknown_field(key, T::ENV_KEYS));
|
||||
};
|
||||
if values.contains_key(key) {
|
||||
return Err(serde::de::Error::duplicate_field(key));
|
||||
}
|
||||
values.insert(key, value);
|
||||
}
|
||||
for key in T::ENV_KEYS {
|
||||
if !values.contains_key(key) {
|
||||
return Err(serde::de::Error::missing_field(key));
|
||||
}
|
||||
}
|
||||
let values = values.into_iter().collect();
|
||||
let entry = EnvEntry::<T>::new_from_values(values);
|
||||
Ok(entry)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct OpenBaoKvEntry<T> {
|
||||
data: OpenBaoKvEntryData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct OpenBaoKvEntryData<T> {
|
||||
data: T,
|
||||
}
|
||||
|
||||
pub fn read_bao_data<T: Endpoint>() -> anyhow::Result<EnvEntry<T>> {
|
||||
let mut cmd = common::proc::Command::new("bao");
|
||||
cmd.args(["kv", "get", "-format=json", "-mount=opentofu", T::NAME]);
|
||||
let result: OpenBaoKvEntry<EnvEntry<T>> = cmd.try_spawn_to_json()?;
|
||||
Ok(result.data.data)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue