跳至内容
liuzhen932 的小窝
返回

在 Debian 12 上安装 step-ca 配置 PKI 和证书颁发机构教程

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-beforenot-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 暴露在互联网上,请考虑以下潜在风险:

默认情况下,任何能够连接到 CA 并满足 ACME 挑战的 ACME 客户端都可以注册到您的 PKI。

/provisioners 端点暴露了提供者的配置,并包含在客户端方便使用。它包括 JWK 加密的私钥、OIDC 客户端凭据和端点 URL 等。

0x07 参考资料

step-ca

Caddy


分享这篇文章:

上一篇
为博客集成 Twtxt:快速接入去中心化社交,兼容 Yarn 社交平台
下一篇
What Does !H Mean in a Traceroute?

人机验证:请刷新页面以加载评论区