ToB企服应用市场:ToB评测及商务社交产业平台

标题: 51从零开始用Rust编写nginx,江湖济急,TLS证书快过期了 [打印本页]

作者: 海哥    时间: 2024-5-12 13:30
标题: 51从零开始用Rust编写nginx,江湖济急,TLS证书快过期了
wmproxy

wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 负载均衡, 静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实现过程分享出来,感爱好的可以一起造个轮子
项目地点

国内: https://gitee.com/tickbh/wmproxy
github: https://github.com/tickbh/wmproxy
设计目标

证书的自动续期,让系统免去证书过期的烦恼,包管系统的正确运行。
关于证书的验证

证书的构成部门:公钥,私钥
公钥部门

公开的信息cert,也称公钥,在nginx体系中通常以.pem结尾
Cert,作为“Certificate”(证书)的缩写,通常用于表示网络安全和加密领域中的数字证书。这些证书是用于证明身份和保障安全性的重要工具,包含了许多关键信息。
一样平常来说,证书中存放的信息重要包括:
此外,证书中还大概包含其他信息,比方证书的序列号、扩展字段等。这些信息对于特定的应用场景大概具有重要意义。
总之,Cert中存放的信息是数字证书的重要构成部门,对于保障网络安全和身份认证具有重要意义。
私钥部门

服务器专用的信息,称为私钥,在nginx体系中通常以.key结尾
私钥的重要作用是在TLS加密通信过程中,对从服务器发送到客户端的数据进行加密,以确保数据的机密性和安全性。当客户端向服务器发送请求时,服务器会使用其私钥对响应数据进行加密,然后发送给客户端。客户端在吸取到加密数据后,会使用服务器公钥进行解密,从而获取到原始数据。
由于私钥的非公开性,假如私钥被泄露,将会对TLS加密通信的安全性造成严重威胁。因此,私钥的生成、存储和使用都需要遵循严格的安全尺度和最佳实践。通常,私钥应该在安全的环境中生成,而且只由授权的职员管理和使用。
在TLS证书的生命周期中,私钥的管理和使用也是非常重要的。一旦私钥丢失或泄露,就需要重新生成新的密钥对和证书,以确保加密通信的安全性。因此,对于TLS证书的私钥部门,必须接纳严格的安全措施,以确保其机密性和安全性。
证书无效的大概

SSL证书大概会由于多种缘故原由而无效。以下是一些常见的环境:
此篇中重要先容证书过期如何维护的大概。
获取过期时间

关于tls的处理库,这里选择的是rustls,查询其相关Api及源码,发现其并未提供Cert的过期时间。这里选择用第三方库x509-certificate来获取证书的过期时间,他并不依赖于openssl,可以在不加载openssl的环境下获取到证书的过期时间。
api相关函数:
  1. pub fn validity_not_after(&self) -> DateTime<Utc>
  2. // Obtain the certificate validity “not after” time.
复制代码
设计要点

源码相关设计

新设计类
  1. /// 包装tls accepter, 用于适应acme及自有证书两种
  2. #[derive(Clone)]
  3. pub struct WrapTlsAccepter {
  4.     /// 最后请求的时间
  5.     pub last: Instant,
  6.     /// 最后成功加载证书的时间
  7.     pub last_success: Instant,
  8.     /// 域名
  9.     pub domain: Option<String>,
  10.     pub accepter: Option<TlsAcceptor>,
  11.     /// 证书的过期时间,将加载证书的时候同步读取
  12.     pub expired: Option<DateTime<Utc>>,
  13.     pub is_acme: bool,
  14. }
复制代码
添加最后成功加载的时间,与全局的加载成功时间做比对。
  1. lazy_static! {
  2.     // 成功加载时间记录,以方便将过期的数据做更新
  3.     static ref SUCCESS_CERT: Mutex<HashMap<String, Instant>> = Mutex::new(HashMap::new());
  4. }
复制代码
判断是否即将到期,到期前一天将自动更新
  1. fn is_tls_will_expired(&self) -> bool {
  2.     if let Some(expire) = &self.expired {
  3.         let now = Utc::now();
  4.         if now.timestamp() > expire.timestamp() - 86400 {
  5.             return true;
  6.         }
  7.     }
  8.     false
  9. }
复制代码
将过期时将重新触发加载:
  1. if self.is_acme && self.is_tls_will_expired() {
  2.     let _ = self.check_and_request_cert();
  3. }
  4. #[cfg(feature = "acme-lib")]
  5. fn check_and_request_cert(&self)  -> Result<(), Error> {
  6.     if self.domain.is_none() {
  7.         return Err(io::Error::new(io::ErrorKind::Other, "未知域名").into());
  8.     }
  9.     {
  10.         let mut map = CACHE_REQUEST
  11.             .lock()
  12.             .map_err(|_| io::Error::new(io::ErrorKind::Other, "Fail get Lock"))?;
  13.         if let Some(last) = map.get(self.domain.as_ref().unwrap()) {
  14.             if last.elapsed() < self.get_delay_time() {
  15.                 return Err(io::Error::new(io::ErrorKind::Other, "等待上次请求结束").into());
  16.             }
  17.         }
  18.         map.insert(self.domain.clone().unwrap(), Instant::now());
  19.     };
  20.     let obj = self.clone();
  21.     std::thread::spawn(move || {
  22.         let _ = obj.request_cert();
  23.     });
  24.     Ok(())
  25. }
复制代码
最后在加载成功后,下一轮的处理中将尝试的加载ssl证书
  1. pub fn update_last(&mut self) {
  2.     if self.accepter.is_none() {
  3.         if self.last.elapsed() > Duration::from_secs(5) {
  4.             self.try_load_cert();
  5.             self.last = Instant::now();
  6.         }
  7.     } else {
  8.         if self.domain.is_none() {
  9.             return;
  10.         }
  11.         let map = SUCCESS_CERT.lock().unwrap();
  12.         let doamin = &self.domain.clone().unwrap();
  13.         if !map.contains_key(doamin) {
  14.             return;
  15.         }
  16.         if self.last_success < map[doamin] && self.last < map[doamin] {
  17.             self.try_load_cert();
  18.             self.last = map[doamin];
  19.         }
  20.     }
  21. }
复制代码
如此一个拥有自动请求且自动更新的acme请求已完成。
假如有细心的已发现相关代码用了feature,基本上便是Cpp中的#ifdef xxx也是用来控制代码是否启用相关的。
关于条件编译 Features

Cargo Feature 是非常强大的机制,可以为大家提供条件编译和可选依赖的高级特性。
相关链接可以参考features
将其中的依赖改成了
  1. acme-lib = { version = "^0.9.1", default-features = true, optional = true}
  2. openssl = { version = "0.10.32", default-features = false, features = ["vendored"], optional = true }
复制代码
由于acme-lib依赖于openssl库,在编译方面大概会相对比力麻烦,需要额外的依赖,此处openssl设置是覆盖acme-lib中的默认features,达到可以不依赖外部openssl库的本领,使用源码编译,所以假如要启用acme-lib本领可以使用
  1. cargo build --features "acme-lib"
  2. 如果openssl不好依赖可以使用来编译系统
  3. cargo build --features "acme-lib openssl"
复制代码
总结

现在免费证书只能申请三个月(之前还能申请十二个月),拥有acme本领对于小的站点来说就比力需要,可以比力好的摆设也不用关心TLS带来的烦恼。
点击 [关注][在看][点赞] 是对作者最大的支持

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4