4. OpenSSL 实战:安装、自签名证书、CSR 生成与证书查看
OpenSSL 这东西,可以说是证书管理领域的瑞士军刀。我做了这么多年运维,几乎每天都要跟它打交道。别看它命令行参数多,其实核心场景就那么几个:装好它、给自己签个证、帮别人生成请求、查查证书里写了啥。今天咱们就把这四个事儿捋清楚。
本章核心脉络:OpenSSL 安装 → 生成自签名证书 → 生成 CSR(证书签名请求)→ 查看证书信息。每一步都是后面章节的基础,别跳过。
4.1 安装 OpenSSL:别以为系统自带就完事了
大部分 Linux 发行版都预装了 OpenSSL,但版本可能很老。我记得有一次排查一个 TLS 握手失败的问题,折腾了两天,最后发现是 OpenSSL 版本太旧,不支持 TLS 1.2。嗯,从那以后我养成了一个习惯:先查版本。
# 查看当前版本
openssl version
# 输出示例:OpenSSL 1.1.1k 25 Mar 2021
如果版本低于 1.1.1,我建议你升级。为什么?1.1.1 是长期支持版,安全更新会持续到 2023 年之后。3.0 系列虽然新,但有些老项目兼容性有问题,生产环境我一般选 1.1.1 系列。
各系统安装方式:
| 操作系统 | 安装命令 | 备注 |
|---|---|---|
| CentOS / RHEL 7 | yum install openssl openssl-devel |
默认 1.0.2,建议加 EPEL 升到 1.1.1 |
| CentOS / RHEL 8+ | dnf install openssl openssl-devel |
默认 1.1.1,够用 |
| Ubuntu / Debian | apt install openssl libssl-dev |
默认 1.1.1 或 3.0 |
| macOS | brew install openssl |
系统自带版本较老,建议用 Homebrew |
| 源码编译 | ./config && make && make install |
适合定制化需求,但维护成本高 |
我的习惯:在 Docker 容器里我直接用官方镜像 alpine:latest 然后 apk add openssl,干净利落。但在物理机或 VM 上,我倾向于用包管理器安装,方便后续用 yum update 统一打补丁。
4.2 生成自签名证书:5 分钟搞定内部测试
自签名证书,说白了就是自己给自己当 CA。开发环境、内网测试、临时 HTTPS 服务,都用得上。但注意,自签名证书浏览器会报不安全,生产环境别这么干。
一步到位法(推荐):
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
# 参数说明:
# -x509 :直接输出自签名证书,不走 CSR 流程
# -newkey rsa:2048 :同时生成 2048 位 RSA 私钥
# -keyout :私钥输出文件
# -out :证书输出文件
# -days 365 :有效期 1 年
# -nodes :私钥不加密(no DES),省去输入密码的麻烦
执行后会交互式问你国家、组织、通用名称等信息。如果你不想交互,加个 -subj 参数:
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt \
-days 365 -nodes \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=Dev/CN=test.example.com"
我曾经踩过的坑:-nodes 这个参数名容易让人误解。它不是“没有节点”的意思,而是“no DES”,即私钥不加密。如果你不加这个参数,每次重启 Nginx 都要手动输入私钥密码,自动化部署时会疯掉。测试环境我建议加上,生产环境看你的安全策略。
分步法(适合教学):
- 先生成私钥:
openssl genrsa -out server.key 2048 - 再生成证书:
openssl req -x509 -key server.key -out server.crt -days 365
两种方式结果一样,一步法更省事。我个人习惯用一步法,除非我需要把私钥单独拿出来做其他用途。
4.3 生成 CSR:给 CA 递交的“申请书”
CSR(Certificate Signing Request)就是你去正规 CA 申请证书时提交的文件。它包含你的公钥和身份信息,CA 审核通过后签个名,就变成正式证书了。
生成 CSR 的标准流程:
# 第一步:生成私钥(如果还没有)
openssl genrsa -out mydomain.key 2048
# 第二步:生成 CSR
openssl req -new -key mydomain.key -out mydomain.csr
# 同样可以加 -subj 免交互
openssl req -new -key mydomain.key -out mydomain.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=www.example.com"
生成的 .csr 文件是文本格式的,你可以用 cat 查看,里面是 Base64 编码的内容。CA 会要求你把这个文件贴到他们的申请页面上。
关键字段说明:
- CN(Common Name):证书绑定的域名。单域名证书就填
www.example.com,通配符证书填*.example.com。这是最重要的字段,填错了证书就没法用。 - O(Organization):公司名称,OV/EV 证书必须和营业执照一致。
- OU(Organizational Unit):部门,比如 IT、DevOps。
- C/ST/L:国家、省、市,按实际情况填就行。
查看 CSR 内容:
openssl req -text -noout -verify -in mydomain.csr
这个命令会解析 CSR 里的公钥、主题、扩展信息等。我每次提交 CSR 前都会跑一遍这个命令,确认信息无误再提交。曾经有一次我手抖把 CN 写成了 www.exmaple.com(拼写错误),CA 审核通过后才发现,重新申请浪费了 2 天时间。所以,提交前一定要检查!
4.4 查看证书信息:诊断问题的第一步
拿到一个证书文件,不管是 .crt、.pem 还是 .cer,第一件事就是看看里面写了啥。OpenSSL 提供了非常强大的查看功能。
查看 PEM 格式证书:
openssl x509 -in server.crt -text -noout
输出内容很长,包含版本、序列号、签名算法、颁发者、有效期、主题、公钥信息、扩展项等。我重点看这几个:
| 字段 | 含义 | 常见问题 |
|---|---|---|
Subject |
证书持有者信息 | CN 域名与实际访问域名不匹配 |
Issuer |
颁发者信息 | 自签名证书 Issuer = Subject |
Not Before / Not After |
有效期起止时间 | 证书过期是最常见的 HTTPS 报错原因 |
Subject Public Key Info |
公钥算法和长度 | 1024 位 RSA 已不安全,建议 2048+ |
X509v3 Subject Alternative Name |
SAN 扩展域名列表 | 缺少 SAN 会导致 Chrome 报错 |
快速检查证书过期:
openssl x509 -in server.crt -noout -dates
# 输出示例:
# notBefore=Jan 1 00:00:00 2024 GMT
# notAfter=Dec 31 23:59:59 2024 GMT
我写了个监控脚本,每天跑一次这个命令,提前 30 天发告警。证书过期导致的线上事故,我见过太多次了。
查看 DER 格式证书(Windows 常用):
openssl x509 -in certificate.der -inform DER -text -noout
查看证书指纹(用于校验证书是否被篡改):
openssl x509 -in server.crt -noout -fingerprint -sha256
# 输出:SHA256 Fingerprint=AB:CD:EF:...
4.5 实战场景:一条命令排查证书问题
最后分享一个我常用的组合拳。当用户反馈“网站打不开,证书错误”时,我会在服务器上跑这条命令:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -text -noout | grep -E "(Subject:|Issuer:|Not Before|Not After|DNS:)"
这条命令做了三件事:
- 用
s_client模拟 TLS 握手,拿到服务器返回的证书 - 用
x509 -text解析证书内容 - 用
grep过滤出关键字段
输出结果一目了然:证书是谁发的、给谁用的、什么时候过期、SAN 里有没有正确的域名。80% 的证书问题,靠这一条命令就能定位。
注意:-servername 参数用于 SNI(Server Name Indication),如果你的服务器托管了多个 HTTPS 站点,不加这个参数可能拿到默认证书,导致诊断结果不准。我刚开始用 s_client 时就犯过这个错,查了半天发现查的是隔壁站点的证书。