首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >开源KMS之vault part14 PKI secret engine实现自建证书颁发体系

开源KMS之vault part14 PKI secret engine实现自建证书颁发体系

原创
作者头像
保持热爱奔赴山海
修改2025-06-29 14:21:57
修改2025-06-29 14:21:57
1.8K0
举报
文章被收录于专栏:DevOpsDevOps

官方文档 https://developer.hashicorp.com/vault/tutorials/pki/pki-engine?variants=vault-deploy%3Aselfhosted

使用场景

企业内部对安全要求比较高的话,会需要启用TLS加密(例如elasticsearch节点、和其它kibana、filebeat等组件之间)。目前外采的付费版的SSL证书基本上有效期都是1年的,每年更换证书既容易遗漏掉,工作量也是挺大的。

因此有时候,我们会考虑使用自建的CA体系。

CA证书体系架构

步骤 0:使用root token登陆vault

代码语言:txt
复制
> export VAULT_ADDR='http://192.168.31.181:8200'

$ vault login hvs.R6BvAMswb8gBJWbFnSTrxI5c                       
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                hvs.R6BvAMswb8gBJWbFnSTrxI5c
token_accessor       vrf79v2YaUzEBmR0jsCqXLJy
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

步骤 1:生成根证书颁发机构

1 在 pki 路径上启用 pki 密钥引擎。

代码语言:txt
复制
$ vault secrets enable pki

2 优化 pki 密钥引擎以颁发最长生存时间 (TTL) 为 10年的证书。

代码语言:txt
复制
$ vault secrets tune -max-lease-ttl=3650d pki

3 生成 example.com 的根 CA,为其指定颁发者名称,并将其证书保存在文件 root_2023_ca.crt 中。

这将生成新的自签名 CA 证书和私有密钥。库 在租约期 (TTL) 结束时自动撤销生成的根。CA 证书对其自己的证书吊销列表 (CRL) 进行签名。

代码语言:txt
复制
$ vault write -field=certificate pki/root/generate/internal \
     common_name="example.com" \
     issuer_name="root-2023" \
     ttl=3650d > root_2023_ca.crt

查看下根证书文件的内容

代码语言:txt
复制
> cat /root/root_2023_ca.crt 
-----BEGIN CERTIFICATE-----
MIIDNTCCAh2gAwIBAgIUZgu7wTTdRf/ChofBK9AisqCDdSswDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjUwNjI4MTAxMzU4WhcNMzUw
NjI2MTAxNDI3WjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALZqsRMNpbc4FPbfqzP7yB/5B1bySPuMKPGC0J1s
3FDqgHU57tP7vK/wODUtCwC62N/PD5xXmu229/LH7I0+HdV1mVpl7lSRM5YifqJN
gjqOaItgGjAPn5V2sdSGWhVBMnybAclPYNDWlZgTMcgKSPPVwJ5vEt1w4sD05Mzg
T63HXQTmtl8ffSqWOp01yVkLIkz3Sr78csJc6YSUh+BycVH/RAX+aXBhg5yNDrJq
ipseLO52Qu2oi9dxqY8P2BwlODAGnxHnFn9TKwX1S6+9INVi0pK1YBP5+c/2XJ4h
sVJxny9/Z+U7/leEYnN7F7HUX0QS3yPVEWDNGH8gzD8tgWkCAwEAAaN7MHkwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMlrRPrcOrLM
BACMOdhV1GxZLUUFMB8GA1UdIwQYMBaAFMlrRPrcOrLMBACMOdhV1GxZLUUFMBYG
A1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBcgeh2NUpD
PMXWZg/04cwuef4mpUwqx31KGNflDoqQRVHtrI149Ma/My6aJka5FHtE68veOFUp
NTHMk8hvdf0NlFaDYKyARJCMdxeQbRvubRwYhJLXGA2fJln5TXONJyjU56GQb2zL
dkAukFJFzFBwDhYISWBWhU74P04CEpN+6jvVnoVxFWK9SlHkrFv+26b1sqn0GwlV
nr90PomwV/RIMowiDgJhYOltr/5Ewssea0ri2mkn3x7KzdbEu+jnw+z3muLzy+i7
NY8KbEMJPEFBkYfpvUenGW2bPT1RZPdM3x29VXWqZiGxaAn9ydeWOR7RBUeHxWo4
QjJ3geelWMr/
-----END CERTIFICATE-----#

4 列出根 CA 的颁发者信息。

代码语言:txt
复制
$ vault list pki/issuers/
Keys
----
10bee018-3e6e-ad07-b16e-42b93a850673

5 您可以使用其 ID 读取颁发者,以获取有关颁发者的证书和其他元数据。使用如下的命令跳过证书内容的输出,但列出颁发者元数据和使用情况信息。

代码语言:txt
复制
$ vault read pki/issuer/$(vault list -format=json pki/issuers/ | jq -r '.[]') | tail -n 13

输出结果如下:
crl_distribution_points           []
delta_crl_distribution_points     []
enable_aia_url_templating         false
issuer_id                         10bee018-3e6e-ad07-b16e-42b93a850673
issuer_name                       root-2023
issuing_certificates              []
key_id                            02cae863-9362-80b9-b250-bfca8046d512
leaf_not_after_behavior           err
manual_chain                      <nil>
ocsp_servers                      []
revocation_signature_algorithm    SHA256WithRSA
revoked                           false
usage                             crl-signing,issuing-certificates,ocsp-signing,read-only

6 为根 CA 创建角色。创建此角色允许在必要时为此方案指定颁发者。这也提供了一种简单的方法,通过名称引用一个颁发者来从一个颁发者过渡到另一个颁发者。

代码语言:txt
复制
$ vault write pki/roles/2023-servers allow_any_name=true

输出结果如下:
Key                                   Value
---                                   -----
allow_any_name                        true
allow_bare_domains                    false
allow_glob_domains                    false
allow_ip_sans                         true
allow_localhost                       true
allow_subdomains                      false
allow_token_displayname               false
allow_wildcard_certificates           true
allowed_domains                       []
allowed_domains_template              false
allowed_other_sans                    []
allowed_serial_numbers                []
allowed_uri_sans                      []
allowed_uri_sans_template             false
allowed_user_ids                      []
basic_constraints_valid_for_non_ca    false
client_flag                           true
cn_validations                        [email hostname]
code_signing_flag                     false
country                               []
email_protection_flag                 false
enforce_hostnames                     true
ext_key_usage                         []
ext_key_usage_oids                    []
generate_lease                        false
issuer_ref                            default
key_bits                              2048
key_type                              rsa
key_usage                             [DigitalSignature KeyAgreement KeyEncipherment]
locality                              []
max_ttl                               0s
no_store                              false
not_after                             n/a
not_before_duration                   30s
organization                          []
ou                                    []
policy_identifiers                    []
postal_code                           []
province                              []
require_cn                            true
serial_number_source                  json-csr
server_flag                           true
signature_bits                        256
street_address                        []
ttl                                   0s
use_csr_common_name                   true
use_csr_sans                          true
use_pss                               false

操作完成后,可以在web ui上看如下:

7 配置 CA 和 CRL URL

代码语言:txt
复制
$ vault write pki/config/urls \
 issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
 crl_distribution_points="$VAULT_ADDR/v1/pki/crl"

输出结果如下:
Key                              Value
---                              -----
crl_distribution_points          [http://192.168.31.181:8200/v1/pki/crl]
delta_crl_distribution_points    []
enable_templating                false
issuing_certificates             [http://192.168.31.181:8200/v1/pki/ca]
ocsp_servers                     []

注意:

当在同一挂载中使用多个颁发者时,建议使用每个颁发者 AIA 字段,而不是全局 (/config/urls) 变体。这是为了正确性:某些应用程序需要这些字段来构建链和自动 CRL 检测。如果它们指向错误的发行者信息,这些应用程序可能会中断。

步骤 2:生成中间 CA

1 首先,在 pki_int 路径启用 pki 密钥引擎。

代码语言:txt
复制
$ vault secrets enable -path=pki_int pki

2 优化 pki_int 密钥引擎以颁发最大生存时间 (TTL) 为  3650d 的证书。

代码语言:txt
复制
$ vault secrets tune -max-lease-ttl=3650d  pki_int

3 执行以下命令生成一个中间文件,并将 CSR 另存为 pki_intermediate.csr。

代码语言:txt
复制
$ vault write -format=json pki_int/intermediate/generate/internal \
     common_name="example.com Intermediate Authority" \
     issuer_name="example-dot-com-intermediate" \
     | jq -r '.data.csr' > pki_intermediate.csr

4 使用根 CA 私有密钥对中间证书进行签名,并将生成的证书另存为 intermediate.cert.pem,这个文件实际上也就是证书链文件

代码语言:txt
复制
$ vault write -format=json pki/root/sign-intermediate \
     issuer_ref="root-2023" \
     csr=@pki_intermediate.csr \
     format=pem_bundle ttl="3650d" \
     | jq -r '.data.certificate' > intermediate.cert.pem

5 签署 CSR 并且根 CA 返回证书后,可以将其导入回 Vault。

代码语言:txt
复制
$ vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem
WARNING! The following warnings were returned from Vault:

  * This mount hasn't configured any authority information access (AIA)
  fields; this may make it harder for systems to find missing certificates
  in the chain or to validate revocation status of certificates. Consider
  updating /config/urls or the newly generated issuer with this information.

Key                 Value
---                 -----
existing_issuers    <nil>
existing_keys       <nil>
imported_issuers    [4deef04b-83a2-ceef-5d13-9527ba044c70 fc640e82-05f1-f95f-7e2e-86356de67c06]
imported_keys       <nil>
mapping             map[4deef04b-83a2-ceef-5d13-9527ba044c70:32f23f46-babc-601d-37a3-8c96c7f8f122 fc640e82-05f1-f95f-7e2e-86356de67c06:]

步骤 3:创建角色

角色是映射到用于生成这些凭证的策略的逻辑名称。它允许配置参数控制证书公用名、备用名称、它们有效的密钥用途等。

创建一个名为 example-dot-com 的角色,该角色允许子域,并将默认颁发者 ref ID 指定为 issuer_ref 的值。

代码语言:txt
复制
$ vault write pki_int/roles/example-dot-com \
     issuer_ref="$(vault read -field=default pki_int/config/issuers)" \
     allowed_domains="example.com" \
     allow_subdomains=true \
     max_ttl="3650d"

输出结果如下:
Key                                   Value
---                                   -----
allow_any_name                        false
allow_bare_domains                    false
allow_glob_domains                    false
allow_ip_sans                         true
allow_localhost                       true
allow_subdomains                      true
allow_token_displayname               false
allow_wildcard_certificates           true
allowed_domains                       [example.com]
allowed_domains_template              false
allowed_other_sans                    []
allowed_serial_numbers                []
allowed_uri_sans                      []
allowed_uri_sans_template             false
allowed_user_ids                      []
basic_constraints_valid_for_non_ca    false
client_flag                           true
cn_validations                        [email hostname]
code_signing_flag                     false
country                               []
email_protection_flag                 false
enforce_hostnames                     true
ext_key_usage                         []
ext_key_usage_oids                    []
generate_lease                        false
issuer_ref                            4deef04b-83a2-ceef-5d13-9527ba044c70
key_bits                              2048
key_type                              rsa
key_usage                             [DigitalSignature KeyAgreement KeyEncipherment]
locality                              []
max_ttl                               87600h
no_store                              false
not_after                             n/a
not_before_duration                   30s
organization                          []
ou                                    []
policy_identifiers                    []
postal_code                           []
province                              []
require_cn                            true
serial_number_source                  json-csr
server_flag                           true
signature_bits                        256
street_address                        []
ttl                                   0s
use_csr_common_name                   true
use_csr_sans                          true
use_pss                               false

操作完成后,在web ui看到的如下:

步骤 4:请求证书

执行以下命令以请求 test.example.com 域 example-dot-com

代码语言:txt
复制
$ vault write pki_int/issue/example-dot-com common_name="test.example.com" ttl="3600d"  

注意这里的ttl值必须小于 步骤3中的max_ttl值。

输出结果比较长,具体如下:

代码语言:txt
复制
Key                 Value
---                 -----
ca_chain            [-----BEGIN CERTIFICATE-----
MIIDsDCCApigAwIBAgIURjYkXHWoC3WreNdW26ozel0iqtYwDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjUwNjI4MTAyNTE1WhcNMzUw
NjI2MTAxNDI3WjAtMSswKQYDVQQDEyJleGFtcGxlLmNvbSBJbnRlcm1lZGlhdGUg
QXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyBRCuWtq
B3Gq0UsWp7A0hHZMJHu/iQv7O9ssw343M/erOhRzI1FtQIkUftvryRhBk+t9gYC3
zBp2zkYE7BPRKzZF8TtjlDvh8EaRfnIRrU4CWpWLMtLY8/vleKuqwXOiyJzgLa4G
ZkqmbuUn0nG62g5JwSVmvPN380sN/6YDu45Fk9FDBQdMLqXkWwMCPhri2lf6g0Ck
uXweONcQFsC1trSrD6aRwz5VGQQ9QwjG/5KHuL50iOD24PUHbB024UK+u82c6a/u
MYCtOQ3anFjaSQzioAHkNEvUi+Nza+sgtLXjgcoFl0/uXjfREUBUN7VYiFUWxfa2
mKGWILp9LcTHTQIDAQABo4HeMIHbMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBQZU/aGxQIzn4UCrUUCiXUXECDsazAfBgNVHSMEGDAW
gBTJa0T63DqyzAQAjDnYVdRsWS1FBTBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUH
MAKGJGh0dHA6Ly8xOTIuMTY4LjMxLjE4MTo4MjAwL3YxL3BraS9jYTA2BgNVHR8E
LzAtMCugKaAnhiVodHRwOi8vMTkyLjE2OC4zMS4xODE6ODIwMC92MS9wa2kvY3Js
MA0GCSqGSIb3DQEBCwUAA4IBAQALcTi6M6CzEXBMRxeMS/DPowAT6FD/fm+0c4rO
v11tRO3SgNNoOuVWd7qy8qKyS7HtEh6nK1faKoRv+NZbrQGFhV5MBPys7mr8BVIZ
fdR0MyeTIgc3efkrw1BsdaMQLf6YYtPREAQo6gy4jVSslXGDqOe8Rg/xw76pc1Xh
bl8x869zGvneitlAb32yZ4bZxV5laxt9edIhjRR+nf7D8l9YSFtU9KpKXUDK3IDq
CAxwkqtjqLncxEqMzoj7W6Ies63kEihljGOCMPs3SUcAshsRKJh6WfMCKHfmYWTw
Tr0/Ng2KqaABt7tIgns7BNzNMRVH1eTFtcJlTxMZA3EadlhL
-----END CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDNTCCAh2gAwIBAgIUZgu7wTTdRf/ChofBK9AisqCDdSswDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjUwNjI4MTAxMzU4WhcNMzUw
NjI2MTAxNDI3WjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALZqsRMNpbc4FPbfqzP7yB/5B1bySPuMKPGC0J1s
3FDqgHU57tP7vK/wODUtCwC62N/PD5xXmu229/LH7I0+HdV1mVpl7lSRM5YifqJN
gjqOaItgGjAPn5V2sdSGWhVBMnybAclPYNDWlZgTMcgKSPPVwJ5vEt1w4sD05Mzg
T63HXQTmtl8ffSqWOp01yVkLIkz3Sr78csJc6YSUh+BycVH/RAX+aXBhg5yNDrJq
ipseLO52Qu2oi9dxqY8P2BwlODAGnxHnFn9TKwX1S6+9INVi0pK1YBP5+c/2XJ4h
sVJxny9/Z+U7/leEYnN7F7HUX0QS3yPVEWDNGH8gzD8tgWkCAwEAAaN7MHkwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMlrRPrcOrLM
BACMOdhV1GxZLUUFMB8GA1UdIwQYMBaAFMlrRPrcOrLMBACMOdhV1GxZLUUFMBYG
A1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBcgeh2NUpD
PMXWZg/04cwuef4mpUwqx31KGNflDoqQRVHtrI149Ma/My6aJka5FHtE68veOFUp
NTHMk8hvdf0NlFaDYKyARJCMdxeQbRvubRwYhJLXGA2fJln5TXONJyjU56GQb2zL
dkAukFJFzFBwDhYISWBWhU74P04CEpN+6jvVnoVxFWK9SlHkrFv+26b1sqn0GwlV
nr90PomwV/RIMowiDgJhYOltr/5Ewssea0ri2mkn3x7KzdbEu+jnw+z3muLzy+i7
NY8KbEMJPEFBkYfpvUenGW2bPT1RZPdM3x29VXWqZiGxaAn9ydeWOR7RBUeHxWo4
QjJ3geelWMr/
-----END CERTIFICATE-----]
certificate         -----BEGIN CERTIFICATE-----
MIIDZjCCAk6gAwIBAgIUaLO3+N91dfMuH2P0MyqzjiFAm5swDQYJKoZIhvcNAQEL
BQAwLTErMCkGA1UEAxMiZXhhbXBsZS5jb20gSW50ZXJtZWRpYXRlIEF1dGhvcml0
eTAeFw0yNTA2MjgxMTMxMDNaFw0zNTA1MDcxMTMxMzJaMBsxGTAXBgNVBAMTEHRl
c3QuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDL
SOHCtZpJYBZkkgMlKUCj/qaz6mZ0QLjO4p78KRcHpjsaTQEfA/b8bVM3CKSSSaR0
Ix5oDM0dsw58Zbk3pbnBCMTowv1gdoKWXNo57Yl3EAomSkJlXfHbUgIsKVwko6rS
4rwM7Z6axbE5D0y+Jacn/q5DsgisDrg7Z69z2xdnG1yHbq9AjJT/xENExHMXouRi
CQfdLSpjsrzYdjKmQIwfluOdHZNYcqmcglB4o5MgqBdc1CeUohCjSzROMG2aavlv
EMQUo3ZaKcuMatKMJDZGGaXu7uailfKwq2ZMcVFz4J3tLV8fDGt+JHnCCR/ETSeW
6LibH+6Y5gWiTd1fX3tNAgMBAAGjgY8wgYwwDgYDVR0PAQH/BAQDAgOoMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUdP3mWQzuiXmRK8eZ
hJ7BVDKqrHMwHwYDVR0jBBgwFoAUGVP2hsUCM5+FAq1FAol1FxAg7GswGwYDVR0R
BBQwEoIQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEASHyHKDTk
vKnXKG8h8uD6i8sumRn5PWD8fagm/b9z/5N0vRAAP3R0Rf+66seyGAdVacfJZT0Y
nnXpLf7B1SIvQZU1LZIz/BznBL62UzrmBdEHzM//0heiInMP2y3Ij+FvrHfMldrj
9JD/lENqs0FL8UIV1tFk/uSe32z1KIxBAPMltQHsLkZZEW8G78+7uhiJiuwmYdKu
RpustZTpguYWuXrIFTPLp0mdCOYtXQ7+DtwxYQkw3d9OYYH/ee7Q8OpWsXpIpNfP
ZPIyqf0DF0p/6vPvGj3AAGYcruafIu38HEM2khCK0v+lnx9DY2Xe9GmXB4zbUuCI
zJSlgNipnyrL0w==
-----END CERTIFICATE-----
expiration          2062150292
issuing_ca          -----BEGIN CERTIFICATE-----
MIIDsDCCApigAwIBAgIURjYkXHWoC3WreNdW26ozel0iqtYwDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjUwNjI4MTAyNTE1WhcNMzUw
NjI2MTAxNDI3WjAtMSswKQYDVQQDEyJleGFtcGxlLmNvbSBJbnRlcm1lZGlhdGUg
QXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyBRCuWtq
B3Gq0UsWp7A0hHZMJHu/iQv7O9ssw343M/erOhRzI1FtQIkUftvryRhBk+t9gYC3
zBp2zkYE7BPRKzZF8TtjlDvh8EaRfnIRrU4CWpWLMtLY8/vleKuqwXOiyJzgLa4G
ZkqmbuUn0nG62g5JwSVmvPN380sN/6YDu45Fk9FDBQdMLqXkWwMCPhri2lf6g0Ck
uXweONcQFsC1trSrD6aRwz5VGQQ9QwjG/5KHuL50iOD24PUHbB024UK+u82c6a/u
MYCtOQ3anFjaSQzioAHkNEvUi+Nza+sgtLXjgcoFl0/uXjfREUBUN7VYiFUWxfa2
mKGWILp9LcTHTQIDAQABo4HeMIHbMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBQZU/aGxQIzn4UCrUUCiXUXECDsazAfBgNVHSMEGDAW
gBTJa0T63DqyzAQAjDnYVdRsWS1FBTBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUH
MAKGJGh0dHA6Ly8xOTIuMTY4LjMxLjE4MTo4MjAwL3YxL3BraS9jYTA2BgNVHR8E
LzAtMCugKaAnhiVodHRwOi8vMTkyLjE2OC4zMS4xODE6ODIwMC92MS9wa2kvY3Js
MA0GCSqGSIb3DQEBCwUAA4IBAQALcTi6M6CzEXBMRxeMS/DPowAT6FD/fm+0c4rO
v11tRO3SgNNoOuVWd7qy8qKyS7HtEh6nK1faKoRv+NZbrQGFhV5MBPys7mr8BVIZ
fdR0MyeTIgc3efkrw1BsdaMQLf6YYtPREAQo6gy4jVSslXGDqOe8Rg/xw76pc1Xh
bl8x869zGvneitlAb32yZ4bZxV5laxt9edIhjRR+nf7D8l9YSFtU9KpKXUDK3IDq
CAxwkqtjqLncxEqMzoj7W6Ies63kEihljGOCMPs3SUcAshsRKJh6WfMCKHfmYWTw
Tr0/Ng2KqaABt7tIgns7BNzNMRVH1eTFtcJlTxMZA3EadlhL
-----END CERTIFICATE-----
private_key         -----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAy0jhwrWaSWAWZJIDJSlAo/6ms+pmdEC4zuKe/CkXB6Y7Gk0B
HwP2/G1TNwikkkmkdCMeaAzNHbMOfGW5N6W5wQjE6ML9YHaCllzaOe2JdxAKJkpC
ZV3x21ICLClcJKOq0uK8DO2emsWxOQ9MviWnJ/6uQ7IIrA64O2evc9sXZxtch26v
QIyU/8RDRMRzF6LkYgkH3S0qY7K82HYypkCMH5bjnR2TWHKpnIJQeKOTIKgXXNQn
lKIQo0s0TjBtmmr5bxDEFKN2WinLjGrSjCQ2Rhml7u7mopXysKtmTHFRc+Cd7S1f
HwxrfiR5wgkfxE0nlui4mx/umOYFok3dX197TQIDAQABAoIBAEh6NbO8F8QtdA5r
WJ+5M4jE1B61Zc3w/XMVrWVuKP3bMJtR9SJfwYGCYPbwJ+zYQL//fWnPlpoOKw4D
HqROfAns3He4faoU1r5RYKTioe5HU7cPJtkJQ5/Uf13LaUTO7aq+mBlr5u57qZIU
eGIa/pvt26fbI+hkXx8e+pkt9gwWO6oQ4UTs0xcBjNf+DndzI2O3tRO9KudnxC3Y
kkDX2ELNkt8C2iSkBNv35ycK9Z2zSi7qMq+DMAues/5FAyKg1fNksXAYuk2qHYFF
tlSBrHPaYyoH7kHE47FSqrR5LrMXk7APEGvcq37Q8cA+ZZBS2hMKMxPWIco9cgTg
nWbPbakCgYEAzL6EO3PAIKyg3uJSckJDbuam0hiNBM3I02ENqO5qz9840yLVac/+
2fYBdA7BTx6lqks5HvygkXfSZ93Cd65xBZqjtH6UfU6HiXwom8MCsbQEOZiNOZRX
901rW2gHZq7swatMqJPWKeZ+Pk+AoK6fxwrS3aF1BnzExvzaMwMlqV8CgYEA/izU
VA0nWJBaly6XW8ZB/++HMGfYwsb9WkZLgNQDTPPO3zDV1XCLX0juFLexWbcw/Z8F
y0li5rfKDZ4EjDMPT3xl0h0lL/mYc1QsTmH35WffIrU6NYGNqRrqA9iPe82VPCvC
mbgZGSBPkDZtLI42K6cDL1Y2Hm0U8vrhZgtcXtMCgYEArYWd3iEoqMiFgsB/LXT5
X6k9ovvJsFOTq4oqoIyHm+tMZqy0AHyWOjWjX7ANpzeLIfukyp1CnGbXvM2WPgZq
pVw8+AD7agO/HQdMB07MHr05g3LF5hHSR7amkQ5mj2EbKLw8OPcqX9KIFdkdY5D7
ux5yPgHTg48E2rx7VRaKubMCgYEAx8IPtWcJDy+UItD5H6V25WAojUBwONQO9U3d
tQfq+CV85igJRk/HGUHF6v5bIbk5hXnfId8xHUZAQ+d2h4DxfXS0yScivMuaprj2
gTu5ic/SrAJmFvsUjFycoh0m1xPBP6Lcs9bd0sN0BFDiCGxT4obFmARXUB5GopfN
YVd4ZwUCgYA5CJC7NG29yMwmwNSMX1seg8D9GhaM7rGimTx0dwyjv8aA5aLCCcqu
g22HZwRuu0IAQfQOw9uK/mkozz1Z4MNWRrU9U+s1Cas9J5Ges7mJir9ERsMCrDaG
T6pq9P+M1AW2ZqabmbXSmquKokyAdZHcMDFRTE0gzoz5JAJDxKhMYA==
-----END RSA PRIVATE KEY-----
private_key_type    rsa
serial_number       68:b3:b7:f8:df:75:75:f3:2e:1f:63:f4:33:2a:b3:8e:21:40:9b:9b

说明:

ca_chain : 根证书和中间证书的合并,将这个证书的下半截(也就是根CA证书)文件导入到windows的“收信任的根证书颁发机构”。

issuing_ca : 中间证书,将这个证书文件导入到windows的“中间证书颁发机构”

certificate : 域名证书,放到nginx的ssl_certificate

private_key :test.example.com 的私钥,放到nginx的ssl_certificate_key

将 certificate 段 的内容 另存为 test.example.com.crt

代码语言:txt
复制
-----BEGIN CERTIFICATE-----
MIIDZjCCAk6gAwIBAgIUaLO3+N91dfMuH2P0MyqzjiFAm5swDQYJKoZIhvcNAQEL
BQAwLTErMCkGA1UEAxMiZXhhbXBsZS5jb20gSW50ZXJtZWRpYXRlIEF1dGhvcml0
eTAeFw0yNTA2MjgxMTMxMDNaFw0zNTA1MDcxMTMxMzJaMBsxGTAXBgNVBAMTEHRl
c3QuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDL
SOHCtZpJYBZkkgMlKUCj/qaz6mZ0QLjO4p78KRcHpjsaTQEfA/b8bVM3CKSSSaR0
Ix5oDM0dsw58Zbk3pbnBCMTowv1gdoKWXNo57Yl3EAomSkJlXfHbUgIsKVwko6rS
4rwM7Z6axbE5D0y+Jacn/q5DsgisDrg7Z69z2xdnG1yHbq9AjJT/xENExHMXouRi
CQfdLSpjsrzYdjKmQIwfluOdHZNYcqmcglB4o5MgqBdc1CeUohCjSzROMG2aavlv
EMQUo3ZaKcuMatKMJDZGGaXu7uailfKwq2ZMcVFz4J3tLV8fDGt+JHnCCR/ETSeW
6LibH+6Y5gWiTd1fX3tNAgMBAAGjgY8wgYwwDgYDVR0PAQH/BAQDAgOoMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUdP3mWQzuiXmRK8eZ
hJ7BVDKqrHMwHwYDVR0jBBgwFoAUGVP2hsUCM5+FAq1FAol1FxAg7GswGwYDVR0R
BBQwEoIQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEASHyHKDTk
vKnXKG8h8uD6i8sumRn5PWD8fagm/b9z/5N0vRAAP3R0Rf+66seyGAdVacfJZT0Y
nnXpLf7B1SIvQZU1LZIz/BznBL62UzrmBdEHzM//0heiInMP2y3Ij+FvrHfMldrj
9JD/lENqs0FL8UIV1tFk/uSe32z1KIxBAPMltQHsLkZZEW8G78+7uhiJiuwmYdKu
RpustZTpguYWuXrIFTPLp0mdCOYtXQ7+DtwxYQkw3d9OYYH/ee7Q8OpWsXpIpNfP
ZPIyqf0DF0p/6vPvGj3AAGYcruafIu38HEM2khCK0v+lnx9DY2Xe9GmXB4zbUuCI
zJSlgNipnyrL0w==
-----END CERTIFICATE-----

将 private_key 段 的内容 另存为 test.example.com.key

代码语言:txt
复制
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAy0jhwrWaSWAWZJIDJSlAo/6ms+pmdEC4zuKe/CkXB6Y7Gk0B
HwP2/G1TNwikkkmkdCMeaAzNHbMOfGW5N6W5wQjE6ML9YHaCllzaOe2JdxAKJkpC
ZV3x21ICLClcJKOq0uK8DO2emsWxOQ9MviWnJ/6uQ7IIrA64O2evc9sXZxtch26v
QIyU/8RDRMRzF6LkYgkH3S0qY7K82HYypkCMH5bjnR2TWHKpnIJQeKOTIKgXXNQn
lKIQo0s0TjBtmmr5bxDEFKN2WinLjGrSjCQ2Rhml7u7mopXysKtmTHFRc+Cd7S1f
HwxrfiR5wgkfxE0nlui4mx/umOYFok3dX197TQIDAQABAoIBAEh6NbO8F8QtdA5r
WJ+5M4jE1B61Zc3w/XMVrWVuKP3bMJtR9SJfwYGCYPbwJ+zYQL//fWnPlpoOKw4D
HqROfAns3He4faoU1r5RYKTioe5HU7cPJtkJQ5/Uf13LaUTO7aq+mBlr5u57qZIU
eGIa/pvt26fbI+hkXx8e+pkt9gwWO6oQ4UTs0xcBjNf+DndzI2O3tRO9KudnxC3Y
kkDX2ELNkt8C2iSkBNv35ycK9Z2zSi7qMq+DMAues/5FAyKg1fNksXAYuk2qHYFF
tlSBrHPaYyoH7kHE47FSqrR5LrMXk7APEGvcq37Q8cA+ZZBS2hMKMxPWIco9cgTg
nWbPbakCgYEAzL6EO3PAIKyg3uJSckJDbuam0hiNBM3I02ENqO5qz9840yLVac/+
2fYBdA7BTx6lqks5HvygkXfSZ93Cd65xBZqjtH6UfU6HiXwom8MCsbQEOZiNOZRX
901rW2gHZq7swatMqJPWKeZ+Pk+AoK6fxwrS3aF1BnzExvzaMwMlqV8CgYEA/izU
VA0nWJBaly6XW8ZB/++HMGfYwsb9WkZLgNQDTPPO3zDV1XCLX0juFLexWbcw/Z8F
y0li5rfKDZ4EjDMPT3xl0h0lL/mYc1QsTmH35WffIrU6NYGNqRrqA9iPe82VPCvC
mbgZGSBPkDZtLI42K6cDL1Y2Hm0U8vrhZgtcXtMCgYEArYWd3iEoqMiFgsB/LXT5
X6k9ovvJsFOTq4oqoIyHm+tMZqy0AHyWOjWjX7ANpzeLIfukyp1CnGbXvM2WPgZq
pVw8+AD7agO/HQdMB07MHr05g3LF5hHSR7amkQ5mj2EbKLw8OPcqX9KIFdkdY5D7
ux5yPgHTg48E2rx7VRaKubMCgYEAx8IPtWcJDy+UItD5H6V25WAojUBwONQO9U3d
tQfq+CV85igJRk/HGUHF6v5bIbk5hXnfId8xHUZAQ+d2h4DxfXS0yScivMuaprj2
gTu5ic/SrAJmFvsUjFycoh0m1xPBP6Lcs9bd0sN0BFDiCGxT4obFmARXUB5GopfN
YVd4ZwUCgYA5CJC7NG29yMwmwNSMX1seg8D9GhaM7rGimTx0dwyjv8aA5aLCCcqu
g22HZwRuu0IAQfQOw9uK/mkozz1Z4MNWRrU9U+s1Cas9J5Ges7mJir9ERsMCrDaG
T6pq9P+M1AW2ZqabmbXSmquKokyAdZHcMDFRTE0gzoz5JAJDxKhMYA==
-----END RSA PRIVATE KEY-----

将ca_chain和issuing_ca 导入到windows后,如下:

test.example.com相关的2个文件,用于nginx中,nginx的配置文件类似如下:

> cat test.example.com.conf   

代码语言:txt
复制
server {
    listen 443 ssl; 
    server_name test.example.com;
	
    ssl_certificate /etc/nginx/cert/test.example.com.crt;
    ssl_certificate_key /etc/nginx/cert/test.example.com.key;
    
    location / {
        proxy_pass http://192.168.31.181:8200;
		
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        proxy_headers_hash_max_size 51200;
        proxy_headers_hash_bucket_size 6400;
        client_max_body_size 100m;

    }
} 

另外,也可以使用如下的方法,把输出的内容直接提取到各个独立的文件中,命令如下:

代码语言:txt
复制
vault write -format=json pki_int/issue/example-dot-com \
  common_name="test.example.com" \
  ttl="3600d" > cert_output.json

# 提取证书并保存为PEM文件
jq -r '.data.certificate' cert_output.json > test.example.com.crt

# 提取私钥并保存为PEM文件
jq -r '.data.private_key' cert_output.json > test.example.com.key

# 提取CA链并保存为PEM文件(中间证书+根证书+issuing_ca)
jq -r '.data.issuing_ca,.data.ca_chain[]' cert_output.json > test.example.com-chain.crt

# 提取中间证书
jq -r '.data.issuing_ca' cert_output.json > test.example.com-issuing_ca.crt

下图是我证书链(根证书+中间证书)导入到本机windows上, 然后把test.example.com的2个密钥文件放到nginx里面。

最终在chrome上访问,可以看到证书是被信任的,并且有效期差不多是10年。

在linux上,导入ca证书链的写法:

代码语言:txt
复制
1将证书文件复制到系统证书目录
cp /root/ca-chain.crt /etc/pki/ca-trust/source/anchors

2 更新系统证书
update-ca-trust

3 导入完成后,执行curl请求测试
curl --verbose https://test.example.com -I

另外,也可以直接申请通配符的域名,写法如下:

vault write pki_int/issue/example-dot-com common_name="*.example.com" ttl="3600d"  

效果如下:

步骤 5:吊销证书

吊销证书时,您可以执行导致 CRL 重新生成的吊销作。当您重新生成 CRL 时,Vault 会从中删除任何过期的证书。

要吊销证书,请执行以下命令,将 <serial_number> 占位符替换为要吊销的证书的实际序列号。

代码语言:txt
复制
vault write pki_int/revoke serial_number=<serial_number>

TIPS: 这里的serial_number ,我是从vault的web ui里面找的,命令行没找到如何列出这个serial_number清单。

例如
$ vault write pki_int/revoke serial_number="1d:ad:32:80:96:1c:7e:53:03:da:92:a1:bb:fc:5b:a4:e3:33:10:ed"
Key                        Value
---                        -----
revocation_time            1751110272
revocation_time_rfc3339    2025-06-28T11:31:12.103996771Z
state                      revoked


$ vault write pki_int/revoke serial_number="10:60:95:1f:96:e6:7e:89:32:e2:3d:3e:57:2a:0e:bd:30:44:0e:2f"
Key                        Value
---                        -----
revocation_time            1751110263
revocation_time_rfc3339    2025-06-28T11:31:03.899983257Z
state                      revoked

吊销后,在web ui可以看到多了个Revocation time的内容,如下图:

步骤 6:删除过期的证书

通过定期删除已过期且超过过期时间的某个缓冲期的证书来保留存储后端和 CRL。

删除已吊销的证书并清理 CRL。

代码语言:txt
复制
vault write pki_int/tidy tidy_cert_store=true tidy_revoked_certs=true

执行完成后,在web ui可以看到如下图:

补充:tidy的作用

  • 过期证书管理:PKI 系统中会存在大量已颁发的证书,这些证书都有各自的有效期。当证书过期后,虽然它们不再被用于正常的安全通信,但仍占用着存储资源。tidy 操作能够识别并清理这些过期的证书,释放 Vault 存储后端的空间,使存储更加高效。例如,在一个繁忙的 PKI 环境中,每天可能会颁发大量短期使用的证书,随着时间推移,过期证书数量增多,tidy 可定期清理这些无用证书。
  • 吊销证书的后续处理:当证书被吊销时,除了将其添加到证书吊销列表(CRL)中外,PKI 存储中可能还保留着与该证书相关的一些陈旧引用或元数据。tidy 操作会查找并移除这些不再需要的信息,保证 PKI 存储中数据的准确性和一致性。例如,某个证书因私钥泄露被吊销,tidy 可确保与该证书相关的额外引用不会残留在系统中,避免潜在的混淆或安全风险。
  • 证书吊销列表维护:证书吊销列表(CRL)记录了所有被吊销的证书。随着吊销证书的增加,CRL 会不断增大。tidy 操作会检查 CRL 中已过期且不再需要保留的吊销记录,并将其删除,保持 CRL 的精简。较小的 CRL 文件在网络传输和客户端验证时更加高效,减少了验证证书吊销状态所需的时间和带宽。

官方文档上, 还有其余的步骤,这里不是必须操作,我们这里就不继续深入了。

步骤 7:生产实操模拟

上面step1-step6的步骤,是基本上照着官方文档演示的。

实际生产中,还有些需要自定义的地方(主要是 path 路径 需要自定义,因为生产的vault可能接入多个域名)

代码语言:txt
复制
步骤 0:使用root token登陆vault
> export VAULT_ADDR='http://192.168.31.181:8200'
$ vault login hvs.R6BvAMswb8gBJWbFnSTrxI5c



步骤 1:生成根证书颁发机构
1 在 sbtest_ca_pki 路径上启用 pki 密钥引擎。
$ vault secrets enable  -path=sbtest_ca_pki pki  # 注意: vault secrets enable pki 的时候,一定要自定义路径(带上域名标识),否则后续再纳管其他域名的自签证书的时候,就不方便区分了。

2 优化 sbtest_ca_pki 密钥引擎以颁发最长生存时间 (TTL) 为 10年的证书。
$ vault secrets tune -max-lease-ttl=3650d sbtest_ca_pki

3 生成 sbtest.com 根 CA,为其指定颁发者名称,并将其证书保存在文件 vault-pki_ca.crt 中。
这将生成新的自签名 CA 证书和私有密钥。库 在租约期 (TTL) 结束时自动撤销生成的根。CA 证书对其自己的证书吊销列表 (CRL) 进行签名。
$ vault write -field=certificate sbtest_ca_pki/root/generate/internal \
     common_name="sbtest.com" \
     issuer_name="sbtest_ca_pki" \
     ttl=3650d > vault-pki_ca.crt

4 列出根 CA 的颁发者信息。  sbtest_ca_pki
$ vault list sbtest_ca_pki/issuers/

5 您可以使用其 ID 读取颁发者,以获取有关颁发者的证书和其他元数据。使用如下的命令跳过证书内容的输出,但列出颁发者元数据和使用情况信息。
$ vault read sbtest_ca_pki/issuer/5170cf42-fefe-e589-225b-1dcd363c381d | tail -n 13

6 为根 CA 创建角色。创建此角色允许在必要时为此方案指定颁发者。这也提供了一种简单的方法,通过名称引用一个颁发者来从一个颁发者过渡到另一个颁发者。
$ vault write sbtest_ca_pki/roles/sbtest-role allow_any_name=true

7 配置 CA 和 CRL URL
$ vault write sbtest_ca_pki/config/urls \
 issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
 crl_distribution_points="$VAULT_ADDR/v1/pki/crl"



步骤 2:生成中间 CA
1 首先,在 sbtest_ca_pki_int 路径启用 pki 密钥引擎。
$ vault secrets enable -path=sbtest_ca_pki_int pki   # 注意: vault secrets enable pki 的时候,一定要自定义路径(带上域名标识),否则后续再纳管其他域名的自签证书的时候,就不方便区分了。

2 优化 sbtest_ca_pki_int 密钥引擎以颁发最大生存时间 (TTL) 为  3650d 的证书。
$ vault secrets tune -max-lease-ttl=3650d  sbtest_ca_pki_int

3 执行以下命令生成一个中间文件,并将 CSR 另存为 pki_intermediate.csr。
$ vault write -format=json sbtest_ca_pki_int/intermediate/generate/internal \
     common_name="sbtest.com Intermediate Authority" \
     issuer_name="sbtest-dot-com-intermediate" \
     | jq -r '.data.csr' > pki_intermediate.csr

4 使用根 CA 私有密钥对中间证书进行签名,并将生成的证书另存为 intermediate.cert.pem,这个文件实际上也就是证书链文件
$ vault write -format=json sbtest_ca_pki/root/sign-intermediate \
     issuer_ref="sbtest_ca_pki" \
     csr=@pki_intermediate.csr \
     format=pem_bundle ttl="3650d" \
     | jq -r '.data.certificate' > intermediate.cert.pem

5 签署 CSR 并且根 CA 返回证书后,可以将其导入回 Vault。
$ vault write sbtest_ca_pki_int/intermediate/set-signed certificate=@intermediate.cert.pem



步骤 3:创建角色
角色是映射到用于生成这些凭证的策略的逻辑名称。它允许配置参数控制证书公用名、备用名称、它们有效的密钥用途等。

创建一个名为 sbtest-dot-com 的角色,该角色允许子域,并将默认颁发者 ref ID 指定为 issuer_ref 的值。
> vault read -field=default sbtest_ca_pki_int/config/issuers 
d0f8c790-e68a-700d-efa7-8cac2f691ded

将上一步的值代入下面命令
$ vault write sbtest_ca_pki_int/roles/sbtest-dot-com \
     issuer_ref="d0f8c790-e68a-700d-efa7-8cac2f691ded" \
     allowed_domains="sbtest.com" \
     allow_subdomains=true \
     max_ttl="3650d"



步骤 4:请求证书
执行以下命令以请求 test.sbtest.com 域 sbtest-dot-com
$ vault write sbtest_ca_pki_int/issue/sbtest-dot-com common_name="test.sbtest.com" ttl="3600d"  
# 注意这里的ttl值必须小于 步骤3中的max_ttl值。

将 ca_chain 段 的内容 另存为 ca-chain.crt
将 certificate 段 的内容 另存为 test.sbtest.com.crt 
将 private_key 段 的内容 另存为 test.sbtest.com.key 

另外,也可以直接申请通配符的域名,写法如下:
vault write sbtest_ca_pki_int/issue/sbtest-dot-com common_name="*.sbtest.com" ttl="3600d"  

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用场景
  • CA证书体系架构
  • 步骤 0:使用root token登陆vault
  • 步骤 1:生成根证书颁发机构
  • 步骤 2:生成中间 CA
  • 步骤 3:创建角色
  • 步骤 4:请求证书
  • 步骤 5:吊销证书
  • 步骤 6:删除过期的证书
  • 步骤 7:生产实操模拟
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档