#[cfg(feature = "aws-secrets")]
mod aws;
#[cfg(feature = "azure-secrets")]
mod azure;
#[cfg(feature = "config-seed")]
mod config;
#[cfg(feature = "gcp-secrets")]
mod gcp;
#[cfg(feature = "k8s-secrets")]
mod k8s;
#[cfg(feature = "keyring")]
mod keyring;
#[cfg(feature = "tee")]
pub mod kms_tee;
mod plaintext;
#[cfg(feature = "vault-secrets")]
mod vault;
#[cfg(feature = "aws-secrets")]
pub use aws::AwsSeedStore;
#[cfg(feature = "azure-secrets")]
pub use azure::AzureSeedStore;
#[cfg(feature = "config-seed")]
pub use config::ConfigSeedStore;
#[cfg(feature = "gcp-secrets")]
pub use gcp::GcpSeedStore;
#[cfg(feature = "k8s-secrets")]
pub use k8s::{K8sSeedStore, from_config as k8s_from_config};
#[cfg(feature = "keyring")]
pub use keyring::KeyringSeedStore;
#[cfg(feature = "tee")]
pub use kms_tee::KmsTeeSeedStore;
pub use plaintext::PlaintextSeedStore;
#[cfg(feature = "vault-secrets")]
pub use vault::{
VaultParams, VaultSeedStore, from_config as vault_from_config, from_params as vault_from_params,
};
#[cfg(feature = "tee")]
use std::future::Future;
#[cfg(feature = "tee")]
use std::pin::Pin;
use std::path::Path;
use crate::config::SecretsConfig;
use vti_common::error::AppError;
pub use vti_common::seed_store::SeedStore;
#[cfg(feature = "tee")]
pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[allow(unused_variables)]
pub fn create_seed_store(
secrets: &SecretsConfig,
data_dir: &Path,
) -> Result<Box<dyn SeedStore>, AppError> {
#[cfg(feature = "aws-secrets")]
if secrets.aws_secret_name.is_some() {
let store = AwsSeedStore::new(
secrets.aws_secret_name.clone().unwrap(),
secrets.aws_region.clone(),
);
return Ok(Box::new(store));
}
#[cfg(feature = "gcp-secrets")]
if secrets.gcp_secret_name.is_some() {
let project = secrets.gcp_project.clone().ok_or_else(|| {
AppError::Config(
"secrets.gcp_project is required when secrets.gcp_secret_name is set".into(),
)
})?;
let store = GcpSeedStore::new(project, secrets.gcp_secret_name.clone().unwrap());
return Ok(Box::new(store));
}
#[cfg(feature = "azure-secrets")]
if secrets.azure_vault_url.is_some() {
let vault_url = secrets.azure_vault_url.clone().unwrap();
let secret_name = secrets
.azure_secret_name
.clone()
.unwrap_or_else(|| "vta-master-seed".to_string());
let store = AzureSeedStore::new(vault_url, secret_name);
return Ok(Box::new(store));
}
#[cfg(feature = "vault-secrets")]
if secrets.vault_addr.is_some() {
let store = vault::from_config(secrets)?;
return Ok(Box::new(store));
}
#[cfg(feature = "k8s-secrets")]
if secrets.k8s_secret_name.is_some() {
let store = k8s::from_config(secrets)?;
return Ok(Box::new(store));
}
#[cfg(feature = "config-seed")]
if secrets.seed.is_some() {
let store = ConfigSeedStore::new(secrets.seed.clone().unwrap());
return Ok(Box::new(store));
}
#[cfg(feature = "keyring")]
{
let store = KeyringSeedStore::new(&secrets.keyring_service, "master_seed");
return Ok(Box::new(store));
}
#[allow(unreachable_code)]
{
if !secrets.allow_plaintext {
return Err(AppError::Config(
"no secure seed-store backend is available (keyring/cloud/Vault/config-seed \
not compiled-in or not configured), and the plaintext file fallback is \
disabled. Configure a secure backend, or set `secrets.allow_plaintext = true` \
to explicitly accept storing the master seed in a cleartext file (dev/test only)."
.into(),
));
}
tracing::warn!(
"secrets.allow_plaintext = true — storing the BIP-32 master seed in a PLAINTEXT \
file. This is NOT secure; use a keyring or cloud/Vault backend in production."
);
let store = PlaintextSeedStore::new(data_dir);
Ok(Box::new(store))
}
}