Skip to content

Commit

Permalink
add exit_on_error adapter setting to handle manual token revocation, …
Browse files Browse the repository at this point in the history
…and hard exit
  • Loading branch information
mkaczanowski committed Nov 27, 2024
1 parent dba492a commit 8b42fe4
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 64 deletions.
6 changes: 1 addition & 5 deletions src/commands/hashicorp/pubkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,9 @@ impl Runnable for PubkeyCommand {

let mut app =
crate::keyring::providers::hashicorp::client::TendermintValidatorApp::connect(
&cfg.adapter.vault_addr,
&signing_key.auth.access_token(),
&self.key_name,
cfg.adapter.endpoints,
cfg.adapter.vault_cacert,
cfg.adapter.vault_skip_verify,
cfg.adapter.cache_pk,
&cfg.adapter,
)
.unwrap_or_else(|e| {
panic!(
Expand Down
6 changes: 1 addition & 5 deletions src/commands/hashicorp/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,9 @@ impl Runnable for TestCommand {
let started_at = Instant::now();

let app = crate::keyring::providers::hashicorp::client::TendermintValidatorApp::connect(
&cfg.adapter.vault_addr,
&signing_key.auth.access_token(),
&self.key_name,
cfg.adapter.endpoints,
cfg.adapter.vault_cacert,
cfg.adapter.vault_skip_verify,
cfg.adapter.cache_pk,
&cfg.adapter,
)
.unwrap_or_else(|e| {
panic!(
Expand Down
10 changes: 4 additions & 6 deletions src/commands/hashicorp/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ impl UploadCommand {

// create app instance
let app = client::TendermintValidatorApp::connect(
&config.adapter.vault_addr,
&config
.keys
.iter()
Expand All @@ -146,10 +145,7 @@ impl UploadCommand {
.auth
.access_token(),
&self.key_name,
config.adapter.endpoints.to_owned(),
config.adapter.vault_cacert.to_owned(),
config.adapter.vault_skip_verify.to_owned(),
config.adapter.cache_pk,
&config.adapter,
)
.unwrap_or_else(|_| {
panic!(
Expand Down Expand Up @@ -313,6 +309,7 @@ mod tests {
payload: Some(ED25519.into()),
payload_file: None,
exportable: false,
payload_format: Some(String::from("base64")),
};

let config = HashiCorpConfig {
Expand All @@ -322,6 +319,7 @@ mod tests {
vault_skip_verify: Some(false),
cache_pk: Some(false),
endpoints: None,
exit_on_error: None,
},
keys: [SigningKeyConfig {
chain_id: tendermint::chain::Id::try_from(CHAIN_ID).unwrap(),
Expand All @@ -340,7 +338,7 @@ mod tests {
.with_body(TOKEN_DATA)
.create();

// upload
// wrap key
let wrapping_key = mock("GET", "/v1/transit/wrapping_key")
.match_header("X-Vault-Token", VAULT_TOKEN)
.with_body(WRAPPING_KEY_RESPONSE)
Expand Down
1 change: 1 addition & 0 deletions src/commands/hashicorp/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn read_config(config_path: &Option<PathBuf>, key_name: &str) -> HashiCorpCo
vault_skip_verify,
cache_pk: Some(false),
endpoints: None,
exit_on_error: None,
},
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/config/provider/hashicorp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ pub struct AdapterConfig {

/// Endpoints configuration for Vault core operations
pub endpoints: Option<VaultEndpointConfig>,

/// Exit tmkms on given error codes. This is especially useful when operator manually revokes the Vault token and tmkms should exit because
/// it can't sign anymore (403) unless the new token is provided
pub exit_on_error: Option<Vec<u16>>,
}

/// Signing key configuration
Expand Down
6 changes: 1 addition & 5 deletions src/keyring/providers/hashicorp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ pub fn init(
}

let mut app = client::TendermintValidatorApp::connect(
&config.adapter.vault_addr,
&key_config.auth.access_token(),
&key_config.key,
config.adapter.endpoints.to_owned(),
config.adapter.vault_cacert.to_owned(),
config.adapter.vault_skip_verify.to_owned(),
config.adapter.cache_pk,
&config.adapter,
)
.unwrap_or_else(|_| {
panic!(
Expand Down
73 changes: 44 additions & 29 deletions src/keyring/providers/hashicorp/client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::error::Error;
use crate::config::provider::hashicorp::VaultEndpointConfig;
use crate::config::provider::hashicorp::AdapterConfig;
use crate::keyring::ed25519;
use crate::keyring::providers::hashicorp::vault_client::{CreateKeyType, VaultClient};
use abscissa_core::prelude::*;
Expand All @@ -18,24 +18,27 @@ unsafe impl Send for TendermintValidatorApp {}

impl TendermintValidatorApp {
pub fn connect(
api_endpoint: &str,
token: &str,
key_name: &str,
endpoints: Option<VaultEndpointConfig>,
ca_cert: Option<String>,
skip_verify: Option<bool>,
enable_pk_cache: Option<bool>,
adapter_config: &AdapterConfig,
) -> Result<Self, Error> {
let vault_client = VaultClient::new(api_endpoint, token, endpoints, ca_cert, skip_verify);
let vault_client = VaultClient::new(
&adapter_config.vault_addr,
token,
adapter_config.endpoints.to_owned(),
adapter_config.vault_cacert.to_owned(),
adapter_config.vault_skip_verify.to_owned(),
adapter_config.exit_on_error.to_owned(),
);

let app = TendermintValidatorApp {
vault_client,
key_name: key_name.to_owned(),
enable_pk_cache,
enable_pk_cache: adapter_config.cache_pk,
pk_cache: None,
};

debug!("Initialized with Vault host at {}", api_endpoint);
debug!("Initialized with Vault host at {}", adapter_config.vault_addr);
app.handshake()?;

Ok(app)
Expand Down Expand Up @@ -116,13 +119,16 @@ mod tests {

// test
let app = TendermintValidatorApp::connect(
&format!("http://{}", server_address()),
TEST_TOKEN,
TEST_KEY_NAME,
None,
None,
None,
Some(false),
&AdapterConfig {
vault_addr: format!("http://{}", server_address()),
endpoints: None,
vault_cacert: None,
vault_skip_verify: None,
exit_on_error: None,
cache_pk: Some(false),
},
);

assert!(app.is_ok());
Expand All @@ -139,13 +145,16 @@ mod tests {

// app
let mut app = TendermintValidatorApp::connect(
&format!("http://{}", server_address()),
TEST_TOKEN,
TEST_KEY_NAME,
None,
None,
None,
Some(true),
&AdapterConfig {
vault_addr: format!("http://{}", server_address()),
endpoints: None,
vault_cacert: None,
vault_skip_verify: None,
exit_on_error: None,
cache_pk: Some(true),
},
)
.expect("Failed to connect");

Expand Down Expand Up @@ -189,13 +198,16 @@ mod tests {

// app
let app = TendermintValidatorApp::connect(
&format!("http://{}", server_address()),
TEST_TOKEN,
TEST_KEY_NAME,
None,
None,
None,
Some(false),
&AdapterConfig {
vault_addr: format!("http://{}", server_address()),
endpoints: Default::default(),
vault_cacert: None,
vault_skip_verify: None,
exit_on_error: None,
cache_pk: Some(false),
},
)
.expect("Failed to connect");

Expand Down Expand Up @@ -235,13 +247,16 @@ mod tests {

// app
let app = TendermintValidatorApp::connect(
&format!("http://{}", server_address()),
TEST_TOKEN,
TEST_KEY_NAME,
None,
None,
None,
Some(false),
&AdapterConfig {
vault_addr: format!("http://{}", server_address()),
endpoints: Default::default(),
vault_cacert: None,
vault_skip_verify: None,
exit_on_error: None,
cache_pk: Some(false),
},
)
.expect("Failed to connect");

Expand Down
63 changes: 49 additions & 14 deletions src/keyring/providers/hashicorp/vault_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use serde_json::Value;
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::pki_types::{pem::PemObject, CertificateDer, ServerName, UnixTime};
use rustls::{DigitallySignedStruct, SignatureScheme};
use std::process;

/// Vault message envelop
#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -170,6 +171,7 @@ pub(crate) struct VaultClient {
api_endpoint: String,
endpoints: VaultEndpointConfig,
token: String,
exit_on_error: Vec<u16>,
}

pub const VAULT_TOKEN: &str = "X-Vault-Token";
Expand All @@ -182,6 +184,7 @@ impl VaultClient {
endpoints: Option<VaultEndpointConfig>,
ca_cert: Option<String>,
skip_verify: Option<bool>,
exit_on_error: Option<Vec<u16>>,
) -> Self {
// this call performs token self lookup, to fail fast
// let mut client = Client::new(host, token)?;
Expand Down Expand Up @@ -233,6 +236,7 @@ impl VaultClient {
endpoints: endpoints.unwrap_or_default(),
agent,
token: token.into(),
exit_on_error: exit_on_error.unwrap_or_default(),
}
}

Expand All @@ -247,14 +251,18 @@ impl VaultClient {
}

// https://developer.hashicorp.com/vault/api-docs/secret/transit#read-key
let data = if let Some(data) = self
let response = self
.agent
.get(&format!(
"{}{}/{}",
self.api_endpoint, self.endpoints.keys, key_name
))
.set(VAULT_TOKEN, &self.token)
.call()?
.call()?;

self.check_response_status_code(&response);

let data = if let Some(data) = response
.into_json::<Root<PublicKeyResponse>>()?
.data
{
Expand Down Expand Up @@ -313,21 +321,27 @@ impl VaultClient {
}

pub fn handshake(&self) -> Result<(), Error> {
let _ = self
let response = self
.agent
.get(&format!(
"{}{}",
self.api_endpoint, self.endpoints.handshake,
))
.set(VAULT_TOKEN, &self.token)
.call()
.map_err(|e| {
Error::Combined(
.call();

match response {
Ok(response) => {
self.check_response_status_code(&response);
Ok(())
}
Err(e) => {
Err(Error::Combined(
"Is \"access_token\" value correct?".into(),
Box::new(e.into()),
)
})?;
Ok(())
))
}
}
}

// vault write transit/sign/cosmoshub-sign-key plaintext=$(base64 <<< "some-data")
Expand All @@ -349,14 +363,18 @@ impl VaultClient {

debug!("signing request: base64 encoded and about to submit for signing...");

let data = if let Some(data) = self
let response = self
.agent
.post(&format!(
"{}{}/{}",
self.api_endpoint, self.endpoints.sign, key_name
))
.set(VAULT_TOKEN, &self.token)
.send_json(body)?
.send_json(body)?;

self.check_response_status_code(&response);

let data = if let Some(data) = response
.into_json::<Root<SignResponse>>()?
.data
{
Expand Down Expand Up @@ -402,14 +420,18 @@ impl VaultClient {
public_key: String,
}

let data = if let Some(data) = self
let response = self
.agent
.get(&format!(
"{}{}",
self.api_endpoint, self.endpoints.wrapping_key
))
.set(VAULT_TOKEN, &self.token)
.call()?
.call()?;

self.check_response_status_code(&response);

let data = if let Some(data) = response
.into_json::<Root<PublicKeyResponse>>()?
.data
{
Expand All @@ -435,7 +457,7 @@ impl VaultClient {
exportable,
};

let _ = self
let response = self
.agent
.post(&format!(
"{}{}/{}/import",
Expand All @@ -444,6 +466,19 @@ impl VaultClient {
.set(VAULT_TOKEN, &self.token)
.send_json(body)?;

self.check_response_status_code(&response);

Ok(())
}

fn check_response_status_code(&self, response: &ureq::Response) {
if self.exit_on_error.contains(&response.status()) {
status_err!(
"Vault API error: {}, exiting due to status code: {}",
response.get_url(),
response.status()
);
process::exit(1)
}
}
}
Loading

0 comments on commit 8b42fe4

Please sign in to comment.