examples/openbao-provision.rs
//! Live, idempotent turn-on of the OpenBao Kubernetes-auth structure for one or
//! more Njord environments — the Rust codification of the previously hand-run
//! `curl` turn-on (see `src/openbao.rs`).
//!
//! ```sh
//! VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN=<root> \
//! cargo run --features openbao --example openbao-provision -- \
//! lab:njord-lab:njord-lab test1:test1-njord:test1 test2:test2-njord:test2
//! ```
//!
//! Each `env:sa:ns` gets a scoped read policy + a k8s-auth role binding that
//! ServiceAccount. Secret VALUES (`secret/data/<env>/app`) are written separately
//! by `tillsynia-admin vault-write`. The `system:auth-delegator` CRB + the Agent
//! injector install are human-approved k8s/helm steps, intentionally not here.
use skidbladnir::openbao::OpenBao;
fn main() -> anyhow::Result<()> {
let mut args: Vec<String> = std::env::args().skip(1).collect();
// optional --k8s-host (default: the in-cluster API address)
let mut host = "https://kubernetes.default.svc".to_string();
if let Some(i) = args.iter().position(|a| a == "--k8s-host") {
host = args.get(i + 1).cloned().unwrap_or(host);
args.drain(i..=(i + 1).min(args.len() - 1));
}
if args.is_empty() {
eprintln!("usage: openbao-provision [--k8s-host URL] env:sa:ns [env:sa:ns ...]");
eprintln!(" e.g. lab:njord-lab:njord-lab test1:test1-njord:test1 test2:test2-njord:test2");
std::process::exit(2);
}
let ob = OpenBao::from_env()?;
ob.enable_kubernetes_auth()?;
ob.configure_kubernetes(&host)?;
println!("k8s auth method enabled + configured (host {host})");
for spec in &args {
let p: Vec<&str> = spec.split(':').collect();
if p.len() != 3 {
anyhow::bail!("bad env spec '{spec}' (want env:sa:ns)");
}
ob.provision_env(p[0], p[1], p[2])?;
println!(
" provisioned {}: read policy + role (sa={} ns={})",
p[0], p[1], p[2]
);
}
println!("done — {} env(s) provisioned (idempotent)", args.len());
Ok(())
}