swarm-secret-client: bound vault requests with a 30s timeout
vaultrs sets no request timeout by default, so a store that accepts a connection and never answers hung every SecretStore call forever. connect_with_identity now sets VAULT_REQUEST_TIMEOUT; a stalled store surfaces as Error::Vault.
This commit is contained in:
parent
7129ee0015
commit
7c16212fdd
2 changed files with 36 additions and 13 deletions
|
|
@ -1,10 +1,12 @@
|
|||
//! A logged-in handle on the store, built from this deployment's environment.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use rustify_derive::Endpoint;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use vaultrs::{
|
||||
api::pki::{requests::GenerateCertificateRequest, responses::GenerateCertificateResponse},
|
||||
client::{Client, VaultClient, VaultClientSettingsBuilder},
|
||||
client::{Client, VaultClient, VaultClientSettings, VaultClientSettingsBuilder},
|
||||
};
|
||||
|
||||
use crate::{Error, mtls, path::MOUNT};
|
||||
|
|
@ -23,6 +25,13 @@ pub const ENV_CACERT: &str = "BAO_CACERT";
|
|||
/// The auth mount a cert login goes through, unless a caller says otherwise.
|
||||
pub const DEFAULT_CERT_MOUNT: &str = "cert";
|
||||
|
||||
/// Upper bound on one request to the store, login included.
|
||||
///
|
||||
/// vaultrs sets no timeout by default, so a store that accepts the connection
|
||||
/// and never answers would hold every [`SecretStore`] call open forever; with
|
||||
/// this bound the call fails with [`Error::Vault`] instead.
|
||||
const VAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
/// Where the store is and which identity we present to it.
|
||||
///
|
||||
/// Separate from the connect so the environment can be checked without one:
|
||||
|
|
@ -37,6 +46,22 @@ pub struct Settings {
|
|||
}
|
||||
|
||||
impl Settings {
|
||||
/// The vaultrs settings for this store, presenting `identity`.
|
||||
fn client_settings(
|
||||
&self,
|
||||
identity: Option<reqwest::Identity>,
|
||||
) -> Result<VaultClientSettings, Error> {
|
||||
let mut builder = VaultClientSettingsBuilder::default();
|
||||
builder
|
||||
.address(self.address.clone())
|
||||
.identity(identity)
|
||||
.timeout(Some(VAULT_REQUEST_TIMEOUT));
|
||||
if let Some(ca) = &self.ca_path {
|
||||
builder.ca_certs(vec![ca.clone()]);
|
||||
}
|
||||
builder.build().map_err(|e| Error::Settings(e.to_string()))
|
||||
}
|
||||
|
||||
/// Read the `BAO_*` variables from the process environment.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -147,16 +172,7 @@ impl SecretStore {
|
|||
) -> Result<Self, Error> {
|
||||
let identity = reqwest::Identity::from_pem(identity_pem).map_err(Error::Tls)?;
|
||||
|
||||
let mut builder = VaultClientSettingsBuilder::default();
|
||||
builder
|
||||
.address(settings.address.clone())
|
||||
.identity(Some(identity));
|
||||
if let Some(ca) = &settings.ca_path {
|
||||
builder.ca_certs(vec![ca.clone()]);
|
||||
}
|
||||
let built = builder
|
||||
.build()
|
||||
.map_err(|e| Error::Settings(e.to_string()))?;
|
||||
let built = settings.client_settings(Some(identity))?;
|
||||
|
||||
let mut inner = VaultClient::new(built)?;
|
||||
let auth = vaultrs::auth::cert::login(&inner, cert_mount, cert_role).await?;
|
||||
|
|
@ -471,6 +487,13 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_client_is_built_with_a_request_timeout() {
|
||||
let s = Settings::from_lookup(full).expect("every required variable is set");
|
||||
let built = s.client_settings(None).expect("settings build");
|
||||
assert_eq!(built.timeout, Some(VAULT_REQUEST_TIMEOUT));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_complete_environment_is_accepted() {
|
||||
// The control: without this, every assertion below could be passing
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ pub enum Error {
|
|||
#[error("the store's settings are unusable: {0}")]
|
||||
Settings(String),
|
||||
|
||||
/// The store refused us, was unreachable, or answered something we could
|
||||
/// not parse.
|
||||
/// The store refused us, was unreachable, did not answer within the
|
||||
/// client's request timeout, or answered something we could not parse.
|
||||
#[error(transparent)]
|
||||
Vault(#[from] Box<vaultrs::error::ClientError>),
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue