Skip to main content

vpg/
vault.rs

1use std::process::Command;
2
3use rootcause::prelude::ResultExt as _;
4use rootcause::report;
5use serde::Deserialize;
6
7/// Response structure from Vault's secret read operations.
8#[derive(Debug, Deserialize)]
9#[expect(dead_code, reason = "Unused fields are kept for completeness")]
10pub struct VaultReadOutput {
11    /// Contains actual secret credentials.
12    pub data: VaultCreds,
13    /// Time-to-live duration in seconds for secret.
14    lease_duration: i32,
15    /// Lease identifier for secret life cycle management.
16    lease_id: String,
17    /// Indicates if lease can be renewed.
18    renewable: bool,
19    /// Unique request identifier for tracing.
20    request_id: String,
21    /// Non-critical operational warnings.
22    warnings: Vec<String>,
23}
24
25/// Database credentials stored in Vault.
26#[derive(Debug, Deserialize)]
27pub struct VaultCreds {
28    /// Database password.
29    pub password: String,
30    /// Database username.
31    pub username: String,
32}
33
34/// Checks and renews Vault authentication using OIDC/Okta if token is invalid.
35///
36/// # Errors
37/// - Executing `vault` fails or returns a non-zero exit status.
38/// - UTF-8 conversion fails.
39/// - OIDC/Okta login fails.
40/// - Token lookup fails for a reason other than permission denied.
41pub fn log_into_vault_if_required() -> rootcause::Result<()> {
42    let token_lookup = Command::new("vault").args(["token", "lookup"]).output()?;
43    if token_lookup.status.success() {
44        return Ok(());
45    }
46    let stderr = std::str::from_utf8(&token_lookup.stderr)
47        .context("error invalid utf-8 stderr")
48        .attach_with(|| format!("cmd=\"vault token lookup\" stderr={:?}", token_lookup.stderr))?
49        .trim();
50    if !stderr.contains("permission denied") {
51        Err(report!("error checking vault token")).attach_with(|| format!("stderr={stderr:?}"))?;
52    }
53
54    let login = Command::new("vault")
55        .args(["login", "-method=oidc", "-path=okta", "--no-print"])
56        .output()?;
57    if !login.status.success() {
58        let stderr = std::str::from_utf8(&login.stderr)
59            .context("error invalid utf-8 stderr")
60            .attach_with(|| format!("cmd=\"vault login\" stderr={:?}", login.stderr))?
61            .trim();
62        Err(report!("error logging into vault")).attach_with(|| format!("stderr={stderr:?}"))?;
63    }
64
65    Ok(())
66}