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”(证书)的缩写,通常用于表示网络安全和加密领域中的数字证书。这些证书是用于证明身份和保障安全性的重要工具,包含了许多关键信息。
一般来说,证书中存放的信息主要包括:
- 证书颁发机构(Certificate Authority,CA)的信息:这包括CA的名称、公钥和证书颁发者的数字签名等。这些信息用于验证证书的合法性和真实性。
- 证书持有者的信息:这通常包括组织或个人的名称、域名、公钥和证书持有者的数字签名等。这些信息用于标识证书的所有者和验证其身份。
- 证书的有效期:证书通常有一个有效期限,包括开始日期和结束日期。这用于确定证书是否仍在有效期内。
此外,证书中还可能包含其他信息,例如证书的序列号、扩展字段等。这些信息对于特定的应用场景可能具有重要意义。
总之,Cert中存放的信息是数字证书的重要组成部分,对于保障网络安全和身份认证具有重要意义。
私钥部分
服务器专用的信息,称为私钥,在nginx体系中通常以
.key
结尾
私钥的主要作用是在TLS加密通信过程中,对从服务器发送到客户端的数据进行加密,以确保数据的机密性和安全性。当客户端向服务器发送请求时,服务器会使用其私钥对响应数据进行加密,然后发送给客户端。客户端在接收到加密数据后,会使用服务器公钥进行解密,从而获取到原始数据。
由于私钥的非公开性,如果私钥被泄露,将会对TLS加密通信的安全性造成严重威胁。因此,私钥的生成、存储和使用都需要遵循严格的安全标准和最佳实践。通常,私钥应该在安全的环境中生成,并且只由授权的人员管理和使用。
在TLS证书的生命周期中,私钥的管理和使用也是非常重要的。一旦私钥丢失或泄露,就需要重新生成新的密钥对和证书,以确保加密通信的安全性。因此,对于TLS证书的私钥部分,必须采取严格的安全措施,以确保其机密性和安全性。
证书无效的可能
SSL证书可能会因为多种原因而无效。以下是一些常见的情况:
- 证书过期:SSL证书有有效期限,一旦过期,浏览器会拒绝连接并显示证书无效的警告。为了避免这种情况,管理员需要定期检查证书的到期日期,并在必要时进行更新或续订。
- 域名不匹配:SSL证书是针对特定的域名颁发的,如果证书中的域名与实际访问的域名不匹配,浏览器也会显示证书无效。这可能是因为证书是为另一个域名颁发的,或者证书中包含的域名拼写错误。
- 证书链不完整:SSL证书通常依赖于一个证书颁发机构(CA)的证书链。如果证书链中的任何证书丢失或损坏,浏览器可能无法验证证书的有效性,并显示证书无效。
- 浏览器不受信任:如果证书颁发机构(CA)的证书被浏览器标记为不受信任或被撤销,那么使用该CA颁发的SSL证书也将被视为无效。
此篇中主要介绍证书过期如何维护的可能。
获取过期时间
关于tls的处理库,这里选择的是rustls,查询其相关Api及源码,发现其并未提供Cert的过期时间。这里选择用第三方库x509-certificate
来获取证书的过期时间,他并不依赖于openssl,可以在不加载openssl的情况下获取到证书的过期时间。
api相关函数:
pub fn validity_not_after(&self) -> DateTime<Utc>
// Obtain the certificate validity “not after” time.
设计要点
- 区分是否为acme的证书(只有acme证书才能自动获取)
- 读取证书的时候获取过期时间
- 在接受证书时判断是否过期
- 未过期,直接继续执行
- 将过期或者已过期未加载,请求新的证书
- 已有新的证书,进行加载
- 保证不会频繁加载
- 用有效的证书进行tls操作
源码相关设计
新设计类
/// 包装tls accepter, 用于适应acme及自有证书两种
#[derive(Clone)]
pub struct WrapTlsAccepter {
/// 最后请求的时间
pub last: Instant,
/// 最后成功加载证书的时间
pub last_success: Instant,
/// 域名
pub domain: Option<String>,
pub accepter: Option<TlsAcceptor>,
/// 证书的过期时间,将加载证书的时候同步读取
pub expired: Option<DateTime<Utc>>,
pub is_acme: bool,
}
添加最后成功加载的时间,与全局的加载成功时间做比对。
lazy_static! {
// 成功加载时间记录,以方便将过期的数据做更新
static ref SUCCESS_CERT: Mutex<HashMap<String, Instant>> = Mutex::new(HashMap::new());
}
判断是否即将到期,到期前一天将自动更新
fn is_tls_will_expired(&self) -> bool {
if let Some(expire) = &self.expired {
let now = Utc::now();
if now.timestamp() > expire.timestamp() - 86400 {
return true;
}
}
false
}
将过期时将重新触发加载:
if self.is_acme && self.is_tls_will_expired() {
let _ = self.check_and_request_cert();
}
#[cfg(feature = "acme-lib")]
fn check_and_request_cert(&self) -> Result<(), Error> {
if self.domain.is_none() {
return Err(io::Error::new(io::ErrorKind::Other, "未知域名").into());
}
{
let mut map = CACHE_REQUEST
.lock()
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Fail get Lock"))?;
if let Some(last) = map.get(self.domain.as_ref().unwrap()) {
if last.elapsed() < self.get_delay_time() {
return Err(io::Error::new(io::ErrorKind::Other, "等待上次请求结束").into());
}
}
map.insert(self.domain.clone().unwrap(), Instant::now());
};
let obj = self.clone();
std::thread::spawn(move || {
let _ = obj.request_cert();
});
Ok(())
}
最后在加载成功后,下一轮的处理中将尝试的加载ssl证书
pub fn update_last(&mut self) {
if self.accepter.is_none() {
if self.last.elapsed() > Duration::from_secs(5) {
self.try_load_cert();
self.last = Instant::now();
}
} else {
if self.domain.is_none() {
return;
}
let map = SUCCESS_CERT.lock().unwrap();
let doamin = &self.domain.clone().unwrap();
if !map.contains_key(doamin) {
return;
}
if self.last_success < map[doamin] && self.last < map[doamin] {
self.try_load_cert();
self.last = map[doamin];
}
}
}
如此一个拥有自动请求且自动更新的acme请求已完成。
如果有细心的已发现相关代码用了feature,基本上等于Cpp中的#ifdef xxx
也是用来控制代码是否启用相关的。
关于条件编译 Features
Cargo Feature 是非常强大的机制,可以为大家提供条件编译和可选依赖的高级特性。
相关链接可以参考features
将其中的依赖改成了
acme-lib = { version = "^0.9.1", default-features = true, optional = true}
openssl = { version = "0.10.32", default-features = false, features = ["vendored"], optional = true }
因为acme-lib
依赖于openssl库,在编译方面可能会相对比较麻烦,需要额外的依赖,此处openssl配置是覆盖acme-lib中的默认features,达到可以不依赖外部openssl库的能力,使用源码编译,所以如果要启用acme-lib能力可以使用
cargo build --features "acme-lib"
如果openssl不好依赖可以使用来编译系统
cargo build --features "acme-lib openssl"
总结
现在免费证书只能申请三个月(之前还能申请十二个月),拥有acme能力对于小的站点来说就比较需要,可以比较好的部署也不用关心TLS带来的烦恼。
点击 [关注],[在看],[点赞] 是对作者最大的支持
51从零开始用Rust编写nginx,江湖救急,TLS证书快过期了的更多相关文章
- bloom-server 基于 rust 编写的 rest api cache 中间件
bloom-server 基于 rust 编写的 rest api cache 中间件,他位于lb 与api worker 之间,使用redis 作为缓存内容存储, 我们需要做的就是配置proxy,同 ...
- centos LNMP第一部分环境搭建 LAMP LNMP安装先后顺序 php安装 安装nginx 编写nginx启动脚本 懒汉模式 mv /usr/php/{p.conf.default,p.conf} php运行方式SAPI介绍 第二十三节课
centos LNMP第一部分环境搭建 LAMP安装先后顺序 LNMP安装先后顺序 php安装 安装nginx 编写nginx启动脚本 懒汉模式 mv /usr/local/php/{ ...
- [转帖]一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS
一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS https://home.cnblogs.com/u/beyang/ 一台服务器,两个域名 首先购买https,获取到CA证 ...
- CentOS6.5 下在Nginx中添加SSL证书以支持HTTPS协议访问
参考文献: 1. NginxV1.8.0安装与配置 2. CentOS下在Nginx中添加SSL证书以支持HTTPS协议访问 3. nginx配置ssl证书的方法 4.nginx强制使用https访问 ...
- nginx配置多个TLS证书,以及TLS SNI简介
背景 原来申请的正式域名备案通过,TLS证书也申请了.之前使用的临时域名和证书作为测试环境使用.于是要在单个ECS主机上配置nginx多个证书和多个域名. 实践 nginx部署多个TLS证书很简单,在 ...
- 使用vault pki 为nginx 生成tls 证书文件
关于vault pki 管理的使用的可以参考官方文档或者docker-vault 以下演示一个简单的基于vault pki 为nginx 提供tls 证书 项目环境配置 nginx 配置文件 wo ...
- SHELL编写NGINX服务控制脚本
使用源码包安装的Nginx没办法使用"service nginx start"或"/etc/init.d/nginx start"进行操作和控制,所以写了以下的 ...
- 从零开始学 Java - 利用 Nginx 负载均衡实现 Web 服务器更新不影响访问
还记得那些美妙的夜晚吗 你洗洗打算看一个小电影就睡了,这个时候突然想起来今天晚上是服务器更新的日子,你要在凌晨时分去把最新的代码更新到服务器,以保证明天大家一觉醒来打开网站,发现昨天的 Bug 都不见 ...
- 编写Nginx启停服务脚本
在/etc/init.d/目录下创建脚本 vim /etc/init.d/nginx 编写脚本内容:(其中下面2行需要根据情况自行修改) nginxd=/opt/nginx/sbin/nginx ng ...
- 脚本编写 nginx 启动
#!bin/bash#功能:本脚本编写完成后,放置在/etc/init.d/目录下,就可以被 Linux 系统自动识别到该脚本.#如果本脚本命名为/etc/init.d/nginx,则 service ...
随机推荐
- 转载:ubuntu各个版本的发行时间和停止支持的时间,更新到最新版和代号。
版本:20.10 代号:Groovy Gorilla 发布时间:2020/10/22 版本:20.04 LTS 代号:Focal Fossa 发布时间:2020/4/23 版本:19.10 ...
- [转载]关于NSA的EternalBlue(永恒之蓝) ms17-010漏洞利用
2017年5月19日 感谢原作者:http://www.cnblogs.com/cnbluerain/ 好久没有用这个日志了,最近WannaCry横行,媒体铺天盖地的报道,我这 ...
- vue中jsx
//item.vue 文件如下 <template> <div> <h1 v-if="id===1"> <slot></slo ...
- 【记录一个问题】golang 中的 ecdsa(椭圆曲线加密) 算法很慢,因为用到了系统调用
代码中使用了椭圆曲线算法来签名,实际运行中发现不够快: func BenchmarkECDSA(b *testing.B) { privateKeyInst, err := parseSignatur ...
- MongoDB 选型介绍
什么是 MongoDB 前言 MongoDB 的主要特性 MongoDB 对比关系型数据库 MySQL 什么时候考虑 MongoDB 参考 什么是 MongoDB 前言 MongoDB 是一个开源.高 ...
- 8.5 Windows驱动开发:内核注册表增删改查
注册表是Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息,注册表是一个巨大的树形结构,无论在应用层还是内核层操作注册表都有独立的API函数可以使用,而在内核中读写注册表则需要使用内 ...
- 2.3 CE修改器:浮点数扫描
本关需要使用 Cheat Engine 工具对浮点数进行扫描,完成修改任务.浮点数是一种带有小数点的数值,通过"浮点数"扫描方式进行修改.本关中,健康值为单精度浮点数,弹药值为双精 ...
- 利用Docker、云服务器、mongodb搭建自己的测试平台
准备一个云服务器 购买一个云服务器,在阿里云,腾讯云上购买即可. 然后创建一个实例,安装Linux操作系统,我安装的是CentOS. 记住账号和密码,可以使用ssh远程登录即可. 搭建测试环境 D ...
- 使用7-zip进行分卷压缩和解分卷压缩(Windows和Linux)
现在一共有10个视频,一共313M,我对该文件夹进行分卷压缩,每个tar包100M,压缩过程如下: Windows环境首先选中所有的压缩包,然后在压缩包上单击鼠标右键,然后选择7-Zip,再选择提取到 ...
- 函数防抖与节流 - js
防抖(debounce)和节流(throttle)是在 高频次调用函数 的场景下,常用的解决方案了.故名思意,可以节省开销,优化体验. 二者的区别: 防抖: 我们让想要执行的函数只在最后一次调用完一小 ...