use std::path::PathBuf;
use opentelemetry_otlp::tonic_types::transport::{Certificate, ClientTlsConfig, Identity};
use serde::{Deserialize, Serialize};
use crate::util::fs::read_file;
pub fn ensure_default_crypto_provider() {
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[non_exhaustive]
pub struct TonicTlsConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub domain: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub ca_certs: Vec<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub identity: Option<TlsIdentity>,
#[serde(default)]
pub assume_http2: bool,
#[serde(default = "crate::util::default_true")]
with_native_roots: bool,
#[serde(default)]
pub use_key_log: bool,
}
impl Default for TonicTlsConfig {
fn default() -> Self {
Self {
domain: None,
ca_certs: Vec::new(),
identity: None,
assume_http2: false,
with_native_roots: true,
use_key_log: false,
}
}
}
impl TonicTlsConfig {
pub async fn to_tonic_config(&self) -> Result<ClientTlsConfig, std::io::Error> {
let mut cfg = ClientTlsConfig::new().assume_http2(self.assume_http2);
if let Some(domain) = &self.domain {
cfg = cfg.domain_name(domain);
}
for path in &self.ca_certs {
let buf = read_file(path).await?;
cfg = cfg.ca_certificate(Certificate::from_pem(buf));
}
if let Some(identity) = &self.identity {
cfg = cfg.identity(identity.to_tonic_identity().await?);
}
if self.with_native_roots {
cfg = cfg.with_native_roots();
}
if self.use_key_log {
cfg = cfg.use_key_log();
}
Ok(cfg)
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[non_exhaustive]
pub struct TlsIdentity {
cert: PathBuf,
key: PathBuf,
}
impl TlsIdentity {
pub async fn to_tonic_identity(&self) -> Result<Identity, std::io::Error> {
let cert = read_file(&self.cert).await?;
let key = read_file(&self.key).await?;
Ok(Identity::from_pem(cert, key))
}
}