vpg/
vault.rs

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