laminar_connectors/postgres/tls/
mod.rs1use std::path::Path;
4use std::str::FromStr;
5
6use tokio_postgres_rustls::MakeRustlsConnect;
7use tokio_rustls::rustls::pki_types::{pem::PemObject, CertificateDer};
8use tokio_rustls::rustls::{ClientConfig, RootCertStore};
9
10use crate::error::ConnectorError;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub enum SslMode {
18 Disable,
20 #[default]
22 VerifyFull,
23}
24
25impl std::fmt::Display for SslMode {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 Self::Disable => write!(f, "disable"),
29 Self::VerifyFull => write!(f, "verify-full"),
30 }
31 }
32}
33
34impl FromStr for SslMode {
35 type Err = String;
36
37 fn from_str(s: &str) -> Result<Self, Self::Err> {
38 match s.to_ascii_lowercase().as_str() {
39 "disable" => Ok(Self::Disable),
40 "verify-full" => Ok(Self::VerifyFull),
41 other => Err(format!("unknown SSL mode: '{other}'")),
42 }
43 }
44}
45
46pub(crate) fn make_rustls_connector(
47 ca_cert_path: Option<&Path>,
48) -> Result<MakeRustlsConnect, ConnectorError> {
49 let _ = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider().install_default();
52
53 let mut roots = RootCertStore::empty();
54 if let Some(path) = ca_cert_path {
55 let certificates = CertificateDer::pem_file_iter(path)
56 .map_err(|error| {
57 ConnectorError::ConfigurationError(format!(
58 "read PostgreSQL CA certificate '{}': {error}",
59 path.display()
60 ))
61 })?
62 .collect::<Result<Vec<_>, _>>()
63 .map_err(|error| {
64 ConnectorError::ConfigurationError(format!(
65 "parse PostgreSQL CA certificate '{}': {error}",
66 path.display()
67 ))
68 })?;
69 if certificates.is_empty() {
70 return Err(ConnectorError::ConfigurationError(format!(
71 "PostgreSQL CA certificate '{}' contains no certificates",
72 path.display()
73 )));
74 }
75 for certificate in certificates {
76 roots.add(certificate).map_err(|error| {
77 ConnectorError::ConfigurationError(format!(
78 "invalid PostgreSQL CA certificate '{}': {error}",
79 path.display()
80 ))
81 })?;
82 }
83 } else {
84 roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
85 }
86
87 let config = ClientConfig::builder()
88 .with_root_certificates(roots)
89 .with_no_client_auth();
90 Ok(MakeRustlsConnect::new(config))
91}
92
93#[cfg(test)]
94mod tests;