step 是一套完整的工具链,让你能够设立自己的证书机构,并颁发、续期,以及吊销证书。对于各位想在家里成立自己的 CA 的小伙伴来说,这无疑是最简单和最方便的方案。
本文全程使用安装有 Starship 的 Bash 终端操作,请在执行本文所提及的任何命令时留意复制的内容!
0x00 基本概念
step-ca
step-ca 是一个在线证书颁发机构,意味着它作为网络服务器运行并接受证书请求。
主动与被动吊销
有两种证书吊销方法:活跃与被动。私有 PKI 默认使用被动吊销。被动吊销不使用证书吊销列表和在线证书签名协议(OCSP),就像你可能熟悉的 Web PKI 一样。
被动吊销证书意味着阻止其在 CA 处续期。这消除了使用 Web PKI 时发生的额外网络请求,因为证书会自行过期。与活跃吊销不同,证书不能立即吊销。因此,证书应具有较短的寿命,以减少被窃取密钥的价值。
我们推荐签发时长不超过 47 天(1128 小时)的证书,这符合自 2029 年 3 月 15 日起 TLS 证书的最大有效期
证书颁发机构(CA)
证书颁发机构(CA)是您用来签发和签署证书的,知道您可以信任使用由根证书签署的任何证书。
0x01 安装组合套件
这里您可以参考官方文档进行安装,因为我们使用 Debian 12 所以使用如下命令进行安装:
root @ homelab in ~
# apt-get update && apt-get install -y --no-install-recommends curl vim gpg ca-certificates
root @ homelab in ~
# curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg -o /etc/apt/trusted.gpg.d/smallstep.asc && echo 'deb [signed-by=/etc/apt/trusted.gpg.d/smallstep.asc] https://packages.smallstep.com/stable/debian debs main' | tee /etc/apt/sources.list.d/smallstep.list
root @ homelab in ~
# apt-get update && apt-get -y install step-cli step-ca
执行命令后查看程序版本,验证安装:
root @ homelab in ~
# step version
Smallstep CLI/0.28.6 (linux/amd64)
Release Date: 2025-03-18T02:24:56Z
root @ homelab in ~
# step-ca version
Smallstep CA/0.28.3 (linux/amd64)
Release Date: 2025-03-18T15:56:22Z
0x02 初始化证书颁发机构
在终端中运行命令 step ca init 来配置我们的 CA。程序会询问我们 DNS 设置和其他信息。
root @ homelab in ~
# step ca init
✔ What would you like to name your new PKI? (e.g. Smallstep): FurCa Infrastructure
✔ What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.]): localhost
✔ What address will your new CA listen at? (e.g. :443): 127.0.0.1:8443
✔ What would you like to name the first provisioner for your new CA? (e.g. [email protected]): [email protected]
✔ What do you want your password to be? [leave empty and we will generate one]: GYi5m2Wk7mUK83
Generating root certificate...
all done!
Generating intermediate certificate...
all done!
✔ Root certificate: /root/.step/certs/root_ca.crt
✔ Root private key: /root/.step/secrets/root_ca_key
✔ Root fingerprint: 702a094e239c9eec6f0dcd0a5f65e595bf7ed6614012825c5fe3d1ae1b2fd6ee
✔ Intermediate certificate: /root/.step/certs/intermediate_ca.crt
✔ Intermediate private key: /root/.step/secrets/intermediate_ca_key
✔ Default configuration: /root/.step/config/defaults.json
✔ Certificate Authority configuration: /root/.step/config/ca.json
Your PKI is ready to go.
请自行填写程序的各个问题,注意 DNS Name 需要是一个基本不会变动,且解析到 CA 服务器的域名,同时注意询问的第一个 Provisioner 名称,目前电子邮件地址作为标识符就可以了。
另外,记下根指纹(Root fingerprint)!在后续步骤中,我们需要它来与其他环境或主机中的 CA 建立信任
0x03 运行我们的证书颁发机构
使用命令 step 运行我们的证书颁发机构,并传递给它刚刚生成的配置文件。
root @ homelab in ~
# step-ca $(step path)/config/ca.json
Please enter the password to decrypt /root/.step/secrets/intermediate_ca_key: GYi5m2Wk7mUK83
2025/05/12 15:02:58 Serving HTTPS on 127.0.0.1:8443 ...
0x04 与我们的证书颁发机构交互
我们可以使用 step ca 命令与 CA 交互,不过开始前,让我们先在终端机器上远程访问一下 CA。
远程访问我们的 CA
在另外一台机器上安装好 step,我们便可以同远程 CA 交互:
┌──(root㉿kali)-[/tmp]
└─# step ca bootstrap --ca-url https://ca.example:8443 --fingerprint 457...9c3
The root certificate has been saved in /root/.step/certs/root_ca.crt.
The authority configuration has been saved in /root/.step/config/defaults.json.
这里的 --ca-url 填写远程可以访问到 CA 的地址,通常是 https://[之前询问的 DNS Name]:[绑定的端口],--fingerprint 可以在远程 CA 上使用 step certificate fingerprint $(step path)/certs/root_ca.crt 获取。
安装根证书
如果我们需要让根证书被信任,我们需要在系统中安装根证书:
┌──(root㉿kali)-[/tmp]
└─# step certificate install $(step path)/certs/root_ca.crt
Certificate /root/.step/certs/root_ca.crt has been installed.
X.509v3 Root CA Certificate (ECDSA P-256) [Serial: 1145...2077]
Subject: FurCa Infrastructure Root CA
Issuer: FurCa Infrastructure Root CA
Valid from: 2025-05-12T00:00:00Z
to: 2035-05-10T00:00:00Z
出现这样的提示就是安装成功了,我们可以开始签发测试证书了。
签发测试证书
我们使用 step ca certificate 命令签发证书,该命令需要传递三个选项:
┌──(root㉿kali)-[/tmp]
└─# step ca certificate example.com example.crt example.key
✔ Provisioner: [email protected] (JWK) [kid: ****]
Please enter the password to decrypt the provisioner key:
✔ CA: https://ca.example:8443
✔ Certificate: example.crt
✔ Private Key: example.key
输入自己的密码,这样就可以成功签发证书了。默认签发的证书是短效证书,时长只有二十四小时,我们可以通过命令来查看:
┌──(root㉿kali)-[/tmp]
└─# step certificate inspect --short example.crt
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2613...8812]
Subject: example.com
Issuer: FurCa Infrastructure Intermediate CA
Provisioner: [email protected] [ID: ****]
Valid from: 2025-05-12T06:30:42Z
to: 2025-05-13T06:30:42Z
为什么证书有效期是二十四小时?
在证书有效期的方面,更长并不总是更安全。较短的有效期限制了私钥被盗用的潜在风险。而且由于所有证书最终都需要更新,不妨使用自动化经常更新。24 小时的默认 TLS 证书有效期相当随意,要更改默认值,请参阅下文。
TLS 证书只需要在连接建立时有效。因此,允许访问敏感数据库的客户端证书可能只需要五分钟的有效期,而客户端可以根据需要完成任务而保持连接。
申请证书时,我们可以调整证书 not-before 和 not-after 参数:
┌──(root㉿kali)-[/tmp]
└─# step ca certificate example.com example.crt example.key --not-after 2m
✔ Provisioner: [email protected] (JWK) [kid: ***]
Please enter the password to decrypt the provisioner key:
✔ CA: https://ca.example:8443
✔ Certificate: example.crt
✔ Private Key: example.key
┌──(root㉿kali)-[/tmp]
└─# step certificate inspect --short example.crt
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2613...8812]
Subject: example.com
Issuer: FurCa Infrastructure Intermediate CA
Provisioner: [email protected] [ID: ****]
Valid from: 2025-05-12T06:30:42Z
to: 2025-05-12T06:33:42Z
注意默认的证书最大有效期为 24 小时。要调整 CA 的全局默认、最小和最大证书有效期,请修改 $(step path)/config/ca.json 配置文件,我们会在下文提及。
下载根证书
有时候我们需要为其他未安装 step 工具的系统安装证书,这时候就需要我们下载根证书然后到对于设备上安装:
step ca root root.crt
# The root certificate has been saved in root.crt.
随后我们就可以在 Windows 上双击 root.crt 并安装至受信任的根证书颁发机构里了。
0x05 配置 ACME-Server 并使用 Caddy 自动化
接下来,我们将修改配置文件(通常位于 $(step path)/config/ca.json)并启用 ACME 协议用于自动化签发证书,随后给出一些 ACME-Client 的示例(如 Certbot 和 Caddy)。
修改配置文件
我们需要修改 .authority.provisioners 的内容,我将修改好的配置和中文注解写在下方,注意复制时删除注解:
{
...
"authority": {
"claims": {
"minTLSCertDuration": "2m", // 最短 TLS 证书时长
"maxTLSCertDuration": "2160h", // 最长 TLS 证书时长,2160 小时是 90 天
"defaultTLSCertDuration": "720h", // 默认 TLS 证书时长,720 小时是 30 天
"disableRenewal": false, // 是否禁用证书续签,默认不禁用
"allowRenewalAfterExpiry": false // 是否允许证书过期后续签,默认不允许
},
"provisioners": [ // 提供者配置
...
{
"type": "ACME", // 类型,这里是 ACME(注意大小写)
"name": "acme-example", // 提供者名称(注意大小写),影响拼接后地址 https://ca.internal/acme/acme-example/directory
"forceCN": true, // 如果未提供通用名称,是否强制将 SAN 之一设置为通用名称
"claims": { // 覆盖在授权机构中设置的默认声明
"maxTLSCertDuration": "720h", // 最长 TLS 证书时长,720 小时是 30 天
"defaultTLSCertDuration": "168h" // 默认 TLS 证书时长,168 小时是 7 天
},
"termsOfService": "", // 包含指向 ACME 服务器服务条款的 URL。默认为空
"website": "", // 包含指向有关 ACME 服务器的更多信息 URL。默认为空
"challenges": [ // 允许的 ACME 挑战类型
"http-01",
"dns-01"
],
"attestationFormats": [ // 允许用于 device-attest-01 挑战的哪些 attestation 格式,保持默认就好
"apple",
"step",
"tpm"
],
"options": { // 模板配置,保持默认就好
"x509": {}
}
}
]
}
...
}
拼接 ACME 目录地址
ACME ACME 服务器目录 URL 将是 https://[CA 公共地址]:[监听端口]/acme/[提供者名称]/directory
注意事项
ACME 客户端和服务器之间的通信始终使用 HTTPS。默认情况下,客户端将使用系统默认信任存储中的公共根证书来验证服务器的 HTTPS 证书。当您连接到 Let’s Encrypt 时,这是可以接受的:它是一个公共 CA,其根证书已经在您的系统默认信任存储中。您的内部根证书不在其中,因此 ACME 客户端到 step-ca 的 HTTPS 连接将失败。
我们可以将 step-ca 的根证书添加到你的系统默认信任存储(例如,使用 step certificate install)来解决这一个问题。
注意:将根证书添加到系统信任存储中是一个全局操作。我们的 CA 颁发的证书将被到处信任,包括在网页浏览器中。
配置 Caddy
这里给出一份 Caddyfile,可以自行对照修改:
foo.internal {
root /var/run/www
tls [email protected] {
ca https://ca.internal/acme/acme-example/directory
}
}
一旦 ACME 服务器通过 HTTP-01 验证了您的域名,证书将在数秒内部署在 Caddy 服务器上,在安装了您 CA 的设备上使用浏览器访问网站将不再出现「安全警告」。
配置 Certbot
sudo REQUESTS_CA_BUNDLE=$(step path)/certs/root_ca.crt \
certbot certonly -n --standalone -d foo.internal \
--server https://ca.internal/acme/acme-example/directory
然后使用 cron 计划任务续签(至于间隔为什么是 15 分钟,因为我在内网签发的都是一小时证书,遥遥领先!):
# ┌───────── 分钟 (0–59)
# │ ┌─────── 小时 (0–23)
# │ │ ┌───── 日期 (1–31)
# │ │ │ ┌─── 月份 (1–12)
# │ │ │ │ ┌─ 星期几 (0–7, 0 和 7 都是周日)
# │ │ │ │ │ ┌─ 实际执行用户
# │ │ │ │ │ │
# └─┴─┴─┴─┴───┴─
*/15 * * * * root REQUESTS_CA_BUNDLE=$(step path)/certs/root_ca.crt certbot -q renew
0x06 其他有用的东西
卸载根证书
玩炸了之后你可以卸载根证书然后重新来过:
step certificate uninstall $(step path)/certs/root_ca.crt
以守护进程方式运行 step-ca
为 CA 添加服务用户
sudo useradd --user-group --system --home /etc/step-ca --shell /bin/false step
sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca) # 如果需要绑定到 443 端口
移动配置文件
mkdir /etc/step-ca # 不执行这一条数据直接爆炸,别问我怎么知道的
sudo mv $(step path)/* /etc/step-ca # 将配置移动到全局 etc config
输入密码
将 CA 密码写入 /etc/step-ca/password.txt
echo 密码 > /etc/step-ca/password.txt
history -c && rm .bash_history
修改配置
修改 /etc/step-ca/config/defaults.json 和 /etc/step-ca/config/ca.json 中不正确的路径,同时安装 jq 修改其他路径:
apt install -y jq # 没安装必须安装,否则数据爆炸,别问我怎么知道的
cat <<< $(jq '.db.dataSource = "/etc/step-ca/db"' /etc/step-ca/config/ca.json) > /etc/step-ca/config/ca.json
赋予权限
为目录设置所有者和权限:
sudo chown -R step:step /etc/step-ca
创建 systemd-unit 文件
wget https://raw.githubusercontent.com/smallstep/certificates/refs/heads/master/systemd/step-ca.service -O /etc/systemd/system/step-ca.service
Fire!
# Rescan the systemd unit files
$ sudo systemctl daemon-reload
# Check the current status of the step-ca service
$ sudo systemctl status step-ca
# Enable and start the `step-ca` process
$ sudo systemctl enable --now step-ca
# Follow the log messages for step-ca
$ sudo journalctl --follow --unit=step-ca
暴露在公共互联网?
通过一些预防措施,step-ca 可能可以暴露给公共互联网
如果您选择将 CA 暴露在互联网上,请考虑以下潜在风险:
- 暴露的、未经身份验证的 ACME 提供者
默认情况下,任何能够连接到 CA 并满足 ACME 挑战的 ACME 客户端都可以注册到您的 PKI。
- CA 提供者的枚举
/provisioners 端点暴露了提供者的配置,并包含在客户端方便使用。它包括 JWK 加密的私钥、OIDC 客户端凭据和端点 URL 等。
0x07 参考资料
step-ca
- Install step-ca
- Certificate Authority Core Concepts
- Running step-ca as a Daemon
- Run your own private CA & ACME server using step-ca