续期了,发出去的仍是旧证书
目标
针对只在启动时读取一次证书的 HTTPS 服务器重现续期事故,并编写两个脚本,用来监控服务器所发出的证书,而不是磁盘上的证书。
为什么重要
续期工具修改文件,服务器发出的是内存。如果其间没有重启,“续期成功”的日志和“即将到期”的告警就会同时为真。素材服务器 /opt/app/tlsserve.py 是只调用一次 load_cert_chain 的 Python HTTPS 服务器,和大多数实际的服务器一样,文件改变了也不会重新读取。本实验的监控脚本,要对评分器另外启动的服务器接受双向(同一文件 FRESH,不同文件 STALE)检查。
步骤
- 创建
/root/renew/ca.key、/root/renew/ca.crt(CN=Lab Root CA)、/root/renew/server.key,以及由 CA 签名的有效期 3 天的/root/renew/v1.crt(SANDNS:www.lab.internal)。 - 把
v1.crt复制为/root/renew/live.crt,把server.key复制为/root/renew/live.key,然后启动python3 /opt/app/tlsserve.py --cert /root/renew/live.crt --key /root/renew/live.key --port 8443。把用openssl s_client取回的证书的serial=这一行保存到/root/renew/02-served.txt。 - 用同一把密钥签发有效期 30 天的
/root/renew/v2.crt,并覆盖到live.crt(这是续期工具所做的事)。不要重启服务器。 - 再次用 s_client 把
serial=保存到/root/renew/04-served.txt,把curl -sk https://127.0.0.1:8443/的正文保存到/root/renew/04-body.txt。磁盘上必须是 v2,而服务器必须仍是 v1。 - 创建
/root/renew/certdiff.sh <인증서파일> <host:port>(占位符依次为证书文件、host:port)。如果磁盘文件与服务器所发证书的 SHA-256 指纹相同,就输出FRESH并以 0 结束;如果不同,就输出STALE并以 1 结束。把针对live.crt和127.0.0.1:8443运行的输出保存到/root/renew/05-detect.txt。 - 结束服务器后重新启动,把 s_client 的
serial=保存到/root/renew/06-served.txt。 - 创建
/root/renew/servedcheck.sh <host:port> <초>(占位符依次为 host:port、秒数)。如果服务器所发证书在该秒数内到期,就输出EXPIRING并以 1 结束,否则输出OK并以 0 结束。把用127.0.0.1:8443 604800运行的输出保存到/root/renew/07-monitor.txt。 - 在
/root/renew/08-report.md中写下 v1 和 v2 的序列号、让服务器读取新文件的方法,以及监控为什么必须看服务器所发的证书,而不是磁盘。
参考
- s_client 会等待标准输入,所以要像
echo | openssl s_client -connect 127.0.0.1:8443 -servername www.lab.internal 2>/dev/null | openssl x509 -noout -serial这样使用。 - 结束服务器:
pkill -f tlsserve.py。重新启动时,请用nohup ... &放到后台。 - 如果要在脚本中把收到的证书暂存为文件,用
openssl x509 -out <임시파일>(占位符为临时文件)接收即可。 - 常见错误:在第 4 步之前重启服务器,事故就消失了。如果第 7 步的监控脚本查看的是磁盘文件,就无法通过评分器的服务器检查。
CA 与 3 天有效的 v1
在 /root/renew/ 中创建 ca.key、ca.crt(CN=Lab Root CA)、server.key,以及 3 天有效的 v1.crt(SAN DNS:www.lab.internal)。
与上一个模块的顺序相同——CA 自签名、带 SAN 的 CSR、用 x509 -req 签名(-copy_extensions copy)。CSR 在第 3 步还要再用,所以请留作 server.csr。
读取服务器所持有的证书
把 v1.crt 复制为 live.crt,把 server.key 复制为 live.key,在 8443 上启动 tlsserve.py,并把用 s_client 取回的 serial= 这一行保存到 /root/renew/02-served.txt。
服务器用 nohup 放到后台,日志输出到 /root/renew/server.log。把 s_client 的全部输出交给 x509 -noout -serial,就会得到 serial= 这一行。
续期——覆盖文件
用同一把密钥签发有效期 30 天的 /root/renew/v2.crt,并覆盖到 live.crt。不要重启服务器。
重新对同一个 CSR 签名即可(-days 30)。serial 会重新编号,到期日会延后。cp v2.crt live.crt 就是续期工具所做的全部。
磁盘是 v2,服务器是 v1
把 s_client 的 serial= 保存到 /root/renew/04-served.txt,把 curl -sk https://127.0.0.1:8443/ 的正文保存到 /root/renew/04-body.txt。
服务器会继续发出启动时读取的内容。两个文件中都必须看到 v1 的 serial,才算重现了事故。curl 的 -k 是因为用的是自建 CA 而关闭验证,正文中有服务器自己报出的 serial。
比较磁盘与服务器的脚本
创建 /root/renew/certdiff.sh <인증서파일> <host:port>(占位符依次为证书文件、host:port)(相同则 FRESH、0,不同则 STALE、1),并把针对 live.crt 和 127.0.0.1:8443 的输出保存到 /root/renew/05-detect.txt。
要取得两个指纹——文件用 x509 -in 文件 -fingerprint -sha256,服务器则把 s_client 的输出交给 x509 -fingerprint -sha256。如果无法从服务器取得证书,返回 ERROR 并以 2 结束会比较好。评分器会用自己的服务器,分别运行同一文件和不同文件两种情形。
重启——服务器读取新文件
结束服务器后重新启动,把 s_client 的 serial= 保存到 /root/renew/06-served.txt。
用 pkill -f tlsserve.py 结束,再用同一条命令重新启动。启动时会重新读取 live.crt,所以这次必须出现 v2 的 serial。
监控服务器所发证书的到期
创建 /root/renew/servedcheck.sh <host:port> <초>(占位符依次为 host:port、秒数)(在该秒数内到期则 EXPIRING、1,否则 OK、0),并把 127.0.0.1:8443 604800 的输出保存到 /root/renew/07-monitor.txt。
用 x509 -out 把 s_client 取回的证书保存到临时文件,再使用 -checkend <秒数> 即可。不能去看磁盘上的 live.crt——评分器会给它自己那台持有 2 天有效证书的服务器设置 7 天窗口,看是否会出现 EXPIRING。
事故报告
在 /root/renew/08-report.md 中写下 v1 和 v2 的序列号、让服务器读取新文件的方法,以及监控为什么必须看服务器所发的证书。
两个 serial 请用 -serial 从 v1.crt、v2.crt 中提取并原样写入。如果写进了“重启”一词和 's_client',评分器就能找到结论。