From 9d655c8944c8fa6de9c91575e40c3ae6f5b3beaa Mon Sep 17 00:00:00 2001 From: xixi Date: Tue, 21 Jun 2022 18:38:13 +0800 Subject: [PATCH] TLS config: support passing cert and key by contents (#49) * add RawFile Signed-off-by: xixi * add tls example Signed-off-by: xixi --- chaos-tproxy-proxy/src/raw_config.rs | 48 ++++++++++++++++++++-------- config-examples/tls_example.yaml | 25 +++++++++++++++ 2 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 config-examples/tls_example.yaml diff --git a/chaos-tproxy-proxy/src/raw_config.rs b/chaos-tproxy-proxy/src/raw_config.rs index 087d948..0bc147a 100644 --- a/chaos-tproxy-proxy/src/raw_config.rs +++ b/chaos-tproxy-proxy/src/raw_config.rs @@ -1,10 +1,8 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::File; -use std::io; -use std::io::BufReader; use std::path::PathBuf; use std::time::Duration; +use std::{fs, io}; use anyhow::{anyhow, Error}; use http::header::{HeaderMap, HeaderName}; @@ -34,11 +32,18 @@ pub struct RawConfig { pub tls: Option, } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(tag = "type", content = "value")] +pub enum RawFile { + Path(PathBuf), + Contents(Vec), +} + #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)] pub struct TLSRawConfig { - pub ca_file: Option, - pub cert_file: PathBuf, - pub key_file: PathBuf, + pub ca_file: Option, + pub cert_file: RawFile, + pub key_file: RawFile, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] @@ -162,6 +167,23 @@ pub(crate) fn try_from_vec( .transpose() } +impl Default for RawFile { + fn default() -> Self { + RawFile::Contents(Default::default()) + } +} + +impl TryFrom for Vec { + type Error = Error; + + fn try_from(value: RawFile) -> Result { + match value { + RawFile::Contents(c) => Ok(c), + RawFile::Path(p) => Ok(fs::read(p)?), + } + } +} + impl TryFrom for Config { type Error = Error; @@ -188,13 +210,12 @@ impl TryFrom for TLSConfig { type Error = Error; fn try_from(raw: TLSRawConfig) -> Result { - let certs = certs(&mut BufReader::new(File::open(raw.cert_file)?)) + let certs = certs(&mut &*Vec::::try_from(raw.cert_file)?) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert")) .map(|mut certs| certs.drain(..).map(Certificate).collect())?; - let keys: Vec = - rsa_private_keys(&mut BufReader::new(File::open(raw.key_file)?)) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key")) - .map(|mut keys| keys.drain(..).map(PrivateKey).collect())?; + let keys: Vec = rsa_private_keys(&mut &*Vec::::try_from(raw.key_file)?) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key")) + .map(|mut keys| keys.drain(..).map(PrivateKey).collect())?; if keys.is_empty() { return Err(anyhow!("empty key")); @@ -202,9 +223,8 @@ impl TryFrom for TLSConfig { let key = keys[0].clone(); let mut root_cert_store = rustls::RootCertStore::empty(); - if let Some(cafile) = &raw.ca_file { - let mut pem = BufReader::new(File::open(cafile)?); - let certs = rustls_pemfile::certs(&mut pem)?; + if let Some(cafile) = raw.ca_file { + let certs = rustls_pemfile::certs(&mut &*Vec::::try_from(cafile)?)?; let trust_anchors = certs.iter().map(|cert| { let ta = webpki::TrustAnchor::try_from_cert_der(&cert[..]).unwrap(); OwnedTrustAnchor::from_subject_spki_name_constraints( diff --git a/config-examples/tls_example.yaml b/config-examples/tls_example.yaml new file mode 100644 index 0000000..e2e7132 --- /dev/null +++ b/config-examples/tls_example.yaml @@ -0,0 +1,25 @@ +proxy_ports: [80, 443, 8080] # proxy will do nothing if empty +rules: + - target: Request + selector: + port: 8080 + path: /example # match all path starts with "/example" + method: GET + actions: + delay: 10s + replace: + body: + update_content_length: false # true by default + contents: + type: TEXT + value: '{"name": "Chaos Mesh", "message": "Hello!"}' +tls: + cert_file: + type: Path + value: /usr/local/example.cert + key_file: + type: Path + value: /usr/local/example.key + # ca_file: + # type: Path + # value: /usr/local/root.cert