如何在Rust中用rustls结合Windows证书存储认证PostgreSQL连接?
在Rust中使用rustls结合PostgreSQL/Diesel(Windows证书存储)实现TLS认证
核心依赖
先把需要的依赖加到Cargo.toml里,根据场景选择同步/异步、是否用Diesel:
# 基础同步版依赖 [dependencies] postgres = "0.19" postgres-rustls = "0.23" rustls = "0.21" rustls-native-certs = "0.6" # 异步版(需添加tokio) postgres = { version = "0.19", features = ["tokio"] } tokio = { version = "1.0", features = ["full"] } # Diesel适配版 diesel = { version = "2.0", features = ["postgres", "r2d2"] }
一、postgres crate + rustls 同步连接示例
直接上代码,关键步骤附注释:
use postgres::Config; use postgres_rustls::MakeRustlsConnect; use rustls::RootCertStore; use rustls_native_certs::load; fn main() -> Result<(), Box<dyn std::error::Error>> { // 1. 加载Windows系统证书存储中的受信任根CA let system_certs = load()?; let mut root_store = RootCertStore::empty(); for cert in system_certs { // 转换为rustls兼容格式并添加到根存储 root_store.add(&rustls::Certificate(cert.0))?; } // 2. 构建rustls客户端配置 let tls_config = rustls::ClientConfig::builder() .with_safe_defaults() // 使用rustls默认安全套件 .with_root_certificates(root_store) // 绑定系统根CA .with_no_client_auth(); // 单向TLS(仅验证服务器证书) // 3. 把rustls配置包装成postgres客户端能识别的TLS连接器 let tls_connector = MakeRustlsConnect::new(tls_config); // 4. 配置PostgreSQL连接参数 let mut db_config = Config::new(); db_config .host("your-db-host") .port(5432) .user("your-db-user") .password("your-db-password") .dbname("your-db-name"); // 5. 建立带TLS的数据库连接 let client = db_config.connect(tls_connector)?; // 测试连接:查询PostgreSQL版本 let rows = client.query("SELECT version();", &[])?; let version: String = rows[0].get(0); println!("Connected to PostgreSQL: {}", version); Ok(()) }
二、异步版postgres连接
异步场景只需调整连接逻辑为异步调用:
use postgres::Config; use postgres_rustls::MakeRustlsConnect; use rustls::RootCertStore; use rustls_native_certs::load; use tokio; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let system_certs = load()?; let mut root_store = RootCertStore::empty(); for cert in system_certs { root_store.add(&rustls::Certificate(cert.0))?; } let tls_config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); let tls_connector = MakeRustlsConnect::new(tls_config); let mut db_config = Config::new(); db_config .host("your-db-host") .port(5432) .user("your-db-user") .password("your-db-password") .dbname("your-db-name"); // 异步建立连接 let client = db_config.connect(tls_connector).await?; // 异步查询 let rows = client.query("SELECT version();", &[]).await?; let version: String = rows[0].get(0); println!("Connected to PostgreSQL: {}", version); Ok(()) }
三、适配Diesel ORM
Diesel底层依赖postgres crate,只需把TLS连接器传入Diesel的连接管理器:
use diesel::pg::PgConnection; use diesel::r2d2::{ConnectionManager, Pool}; use postgres_rustls::MakeRustlsConnect; use rustls::RootCertStore; use rustls_native_certs::load; fn main() -> Result<(), Box<dyn std::error::Error>> { // 加载系统根CA并构建TLS配置,步骤和之前一致 let system_certs = load()?; let mut root_store = RootCertStore::empty(); for cert in system_certs { root_store.add(&rustls::Certificate(cert.0))?; } let tls_config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); let tls_connector = MakeRustlsConnect::new(tls_config); // 用`new_with_tls`方法创建带TLS的Diesel连接管理器 let db_url = "postgres://your-db-user:your-db-password@your-db-host:5432/your-db-name"; let manager = ConnectionManager::<PgConnection>::new_with_tls(db_url, tls_connector); // 创建连接池(Diesel常用连接池模式) let pool = Pool::builder().build(manager)?; // 从连接池获取连接并测试 let conn = pool.get()?; let version: String = diesel::sql_query("SELECT version()") .get_result(&conn)?; println!("Connected to PostgreSQL via Diesel: {}", version); Ok(()) }
四、双向TLS(客户端证书认证)
如果PostgreSQL服务器要求客户端提供证书,用win-cert-store读取Windows证书存储中的客户端证书:
先添加依赖:
win-cert-store = "0.3"
修改TLS配置部分:
use win_cert_store::Certificate; // ... 前面加载根CA的代码不变 ... // 从Windows证书存储加载客户端证书(按主题名称查找,也可用指纹) let client_cert = Certificate::find() .subject_name("Your Client Certificate Subject") .find_one()?; // 提取证书DER编码和私钥 let cert_der = client_cert.encoded()?; let private_key = client_cert.private_key()?; // 转换为rustls兼容格式 let rustls_cert = rustls::Certificate(cert_der); let rustls_key = rustls::PrivateKey(private_key); // 构建带客户端证书的TLS配置 let tls_config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_client_auth_cert(vec![rustls_cert], rustls_key)?;
注意事项
- 确保PostgreSQL服务器已开启TLS:检查
postgresql.conf中的ssl = on,并配置ssl_cert_file和ssl_key_file rustls-native-certs自动读取Windows"受信任的根证书颁发机构"存储区,无需手动指定CA文件- 客户端证书需放在Windows"个人"证书存储区,且当前程序有权限读取(通常需管理员权限或证书设置为可导出)
内容的提问来源于stack exchange,提问作者Tom Kaufman
相关产品推荐
相关产品推荐

