在计算机加密和安全领域中,我们会时常遇到:自签名安全证书。

因为自签名证书签发相对于商业证书流程简单,费用低廉(除了电费几乎不花钱),更新容易。所以在开发领域、甚至一些小众场景下特别常见,比如 K8S / MySQL 集群中的 TLS 认证,一些大的集团、公司的内网服务、网站安全证书、企业路由器设备的管理后台、用于管理企业员工的“安全准入客户端”等不乏使用这个方案。

本篇文章就来聊聊如何快速生成证书,以及如何安装部署到不同的环境中。

写在前面

经常有人说,使用自签名证书不安全,会导致中间人攻击。这里需要为自签名证书“正名”,如果你制作生成的证书被妥善保管(即不泄漏并被二次利用),并将其加入你的有限的设备(自用、团队使用)的证书信任列表中,在明确你的设备访问地址(不涉及DNS攻击),你是不会遇到中间人攻击的。

比如当你遇到类似下面的场景,不一定会遇到不安全的事情,有可能只是管理员忘记换掉过期证书、或者你自己生成证书后,使用了一台没有信任证书的设备进行访问、也可能是管理员压根没有想在公网签发证书,想做一个私有的网站:

常见的网站因为证书问题而产生的警告页面

多数时候我们看到的不安全的证书是因为应用错误配置、有心人基于 DNS 地址攻击、证书过期造成、甚至是我们未曾正确配置证书信任白名单造成的。

一旦我们正确生成证书,在妥善保存证书后,进行了有限设备的白名单设置后,我们的证书和商业证书的使用是几乎没有差别的(除了无法使用 OCSP、EV 证书使用上存在一定额外工作外)。

信任之后,会看到浏览器提示“安全”

那么来聊聊如何快速生成证书。

使用命令行脚本生成自签名证书

最常见和通用的做法便是安装配置一个带有 openssl 环境的系统,然后使用命令行执行类似下面这样的命令:

这里如果你选择不使用配置文件的话,得参考openssl 文档,附带一堆参数,或需要交互式的输入一堆选项,并祈祷在中间每一步没有输入出错,例如下面这样:

相比之下,使用类似下面的配置生成证书会稍微容易那么一些:

类似的脚本,我曾在 Traefik 示例脚本中提到过: https://github.com/soulteary/traefik-example/blob/main/scripts/generate-certs.sh

还有更简单的方案吗?尤其是在有不断修改 DNS、希望使用脚本自动化签订证书的场景下?

快速生成证书

为此我写了一个脚本,并使用容器进行封装,以达到可以使用极其简的命令行来生成证书的目的,并借助容器简化掉了本地需要安装 openssl 依赖的问题,“开箱即用”。相关代码我已经开源,项目地址:https://github.com/soulteary/certs-maker

比如你想生成一个稍微复杂一些的站点证书,只需要执行下面这行命令就足够了:

执行完毕你将会看到类似下面的日志:

以及能够在 ssl 目录中看到我们生成的证书文件。

至于其他的使用方式,比如生成包含多个域名的混合证书、生成单个证书,只需要调整 CERT_DNS 参数的值即可。如果想进一步定制前文提到的证书细节,比如证书签发国家、省份等信息,可以参考开源项目仓库的使用方式,添加其他的参数,这里就不过多赘述了。

使用 docker-compose 生成

如果你希望将命令保存下来,作为代码存储在仓库里,也可以考虑编写一个 compose 文件:

将上面的内容保存为 docker-compose.yml,然后执行 docker-compose up ,你会在 certs 目录看到生成的证书文件。

使用证书

生成证书之后,来聊聊如何使用证书。

在各种系统上导入证书

导入证书可以参考下面的文档,过程都很简单,引导证书,然后重启需要使用证书的应用即可。

在 Java 应用中信任自签名证书

如果你使用的是 Java 应用访问自签名的网站,应用访问过程会出现因为证书错误而拒绝连接的错误。

解决这个问题并不复杂,只需要额外做一点点工作,将证书添加到 keystore 中,重启 Java 应用即可:

这个操作对于证书过期的情况,也同样有效,早先有一篇文章有描述:《使用 Docker 和 Traefik v2 搭建 Confluence 7.3 》

在 Debian / Ubuntu / Alpine 系统中信任证书

对于 Debian / Ubuntu 系统,信任证书相当简单,只需要将证书拷贝到“待安装目录”,然后执行证书更新命令即可:

Alpine 也是一样,考虑我们经常在容器场景中使用它,所以这里直接给出一个完整的Dockerfile 示例:

搭建配合安装证书使用的 Web 服务

上文中如果想在客户端(尤其是手机)上安装证书,一定会遇到跨系统传输文件的问题。为了方便分发和安装,这里可以使用 Nginx 启动一个用于分享证书安装的 Web 服务。

使用更“直观”的方式获取证书

搭建通用服务

我们可以使用 Nginx 的 ngx_http_sub_module 和 ** ngx_http_autoindex_module** 模块构建一个能够自动列举证书目录的服务:

将上面的内容保存为 default.conf 后,再创建一个名为 docker-compose.yml 的配置文件:

然后使用 docker-compose up 启动服务后,使用手机访问页面,就能够看到类似下面的页面,然后使用手机访问证书文件进行安装和信任就可以啦。

更简单的配置方式

上面的模式我们将配置和服务编排文件分拆成了两个文件,考虑到这个 Nginx 配置十分简单,那么我们是否有办法将其简化呢?

答案是有的,通过对 command 命令进行调整,我们可以将 Nginx 配置的创建和服务启动同时写在 docker-compose.yml 编排文件中:

最后

最近入手了三根雷电数据线,快过年了,或许可以折腾一下雷电数据线组网开发。

–EOF