用Hashicorp Vault搭建自己的CA(三)——应用(古法手作)

阅读本篇文章需要先完成上一篇:搭建CA

在上一篇文章中,我们搭建好了一个根CA,用它签发了一个中间CA。今天我们要用这个中间CA给服务器签发证书,并安装。

C 创建一个角色(role)

Vault里面的CA需要一个或多个(取决于您的颗粒度想要对得多齐)角色才可以签发证书。

我将使用默认的中间CA创建一个角色:

1
2
3
4
5
vault write ca-int-x1/roles/cert-test \
     issuer_ref="$(vault read -field=default ca-int-x1/config/issuers)" \
     allowed_domains=<自己的域名,多个用","隔开> \ # 比如"miyunda.com,local"
     allow_subdomains=true \
     max_ttl="720h"

以后想查看它的信息的话:

1
vault read ca-int-x1/roles/cert-test

里面的内容是这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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                       [miyunda.com,local]
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                            d9c746f9-e95d-5856-e5bc-c7149a966814
key_bits                              2048
key_type                              rsa
key_usage                             [DigitalSignature KeyAgreement KeyEncipherment]
locality                              []
max_ttl                               720h
no_store                              false
not_after                             n/a
not_before_duration                   30s
organization                          []
ou                                    []
policy_identifiers                    []
postal_code                           []
province                              []
require_cn                            true
server_flag                           true
signature_bits                        256
street_address                        []
ttl                                   0s
use_csr_common_name                   true
use_csr_sans                          true
use_pss                               false

也可以改,比如我看RSA不顺眼,不想用:

1
vault write ca-int-x1/roles/cert-test key_type=ed25519

D 申请证书

以下命令申请一个证书,其中common_name 是必选项,其它可以不填。它申请了一个带有多SAN DNS的证书,这些FQDN只要有一个能与web服务器的FQDN匹配即可生效。

1
2
3
4
vault write ca-int-x1/issue/cert-test \
common_name="test-1.miyunda.com" \
alt_names="test-1.lab.miyunda.com,web-dev-01.lab.miyunda.com" \
ttl="48h" # 默认是角色里面定义的时间

它会输出信任链、证书及私钥,其中私钥只显示这一次,🎶一旦错过就不在🎶:

E 组装证书:

证书有了,安装到服务器时需要两个文件,信任链+证书是公开展示的,另一个是绝对私密的。其中公开展示的那一部分需要我们手动组装,它将由服务器的证书本身以及信任链一起组成。这样,当web客户端检查web服务器的证书时,可以“顺瓜摸藤”,检查签发web服务器的证书的CA是否在自己的信任列表中。

私钥长这样:

1
2
3
4
5
private_key         -----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApcs68FOhrwWXYFkLh9WVC3K3LWNTLgrm15AIBfnjOtb3qiXw
...
L5Aa3f+UDO0jlVOhXTmsIRi+/HZn9xlpyuYjcUxw2usTFAjSMREEqQ==
-----END RSA PRIVATE KEY-----

而CA信任链(chain of trust)则随时可以查看

1
curl $VAULT_ADDR/v1/ca-int-x1/ca_chain

注:当前版本(v1.17.2)可能有bug,它会在CA的证书最后加一个空行,这个空行会导致Vault的web界面不能显示CA证书信息,一般不影响正常使用,不用理它。

web服务器证书本书也可以随时从Vault下载:

1
2
vault list ca-int-x1/certs
vault kv get -field=certificate ca-int-x1/cert/<sn>

还能显示其信息:

1
2
3
vault read -format=json ca-int-x1/cert/<sn> | \
    jq -r '.data.certificate' | \
    openssl x509 -in - -noout -text

把信任链和单个证书的内容用随便什么文本编辑器甚至cp命令都可以把它们按照下列顺序缝合在一起,和私钥存放在web服务器上。

1
2
3
4
5
6
7
8
9
-----BEGIN CERTIFICATE-----
单个证书在这里,比如test-1.miyunda.com
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
中间CA证书在这里
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
根CA证书在这里
-----END CERTIFICATE-----

F 安装

在web服务器上安装证书的方法那就不一定了,各家产品不同,不过思路都是大同小异:

证书存在一个什么文件夹里,然后web服务器的配置文件改一改。我以一个运行在Debian的Caddy为例,以下操作在web服务器上:

要是不会传文件过去那就直接编辑😂:

1
2
3
sudo mkdir -p /etc/ssl/lab
sudo nano /etc/ssl/lab/web-dev-01_full.pem
sudo nano /etc/ssl/lab/web-dev-01_key.pem

可以用命令查看下信息:

1
openssl x509 -in /etc/ssl/lab/web-dev-01_full.pem -noout -text

我的web服务器运行的是Caddy,Debian的官方源就有:

1
2
sudo apt update
sudo apt install caddy

写一个页面:

1
2
sudo mkdir -p /caddyroot/web-dev-01
sudo nano /caddyroot/web-dev-01/index.html

其内容为:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
    <head>
        <title>Hello nerd</title>
    </head>
    <body>
        <p>我是web-dev-01</p>
    </body>
</html>

Caddy的配置超简单的:

1
sudo nano /etc/caddy/Caddyfile

以下第一行FQDN自己改下,当然需要这台服务器的FQDN能够被DNS正确解析。这个配置文件告诉Caddy我们要用https,还加入了证书的路径。去往web服务器TCP 80的流量会被重定向(301 rewrite)到TCP 443。

1
2
3
4
5
web-dev-01.lab.miyunda.com {
        tls /etc/ssl/lab/web-dev-01_full.pem /etc/ssl/lab/web-dev-01_key.pem
        root * /caddyroot/web-dev-01
        file_server
}

载入新配置

1
2
sudo systemctl start caddy # 要是已经在运行就用reload载入新配置
systemctl status caddy

注:要是喜欢Nginx的话用这个配置:

1
2
3
4
5
6
7
8
9
server {
    listen 443 ssl;
    server_name web-dev-01.lab.miyunda.com;

    ssl_certificate /etc/ssl/lab/web-dev-01_full.pem;
    ssl_certificate_key /etc/ssl/lab/web-dev-01_key.pem;

    root /wwwroot/web-dev-01;
}

G web客户端

图形界面

浏览器访问我们的web服务器时会弹出警告,因为这CA是我们自己搭建的,不被浏览器信任。

默认不信任

企业/组织中的IT管理员可以配置策略给浏览器导入自建CA的证书,用户也可以在每个浏览器上单独导入。有些浏览器维护各自的信任CA列表,有些则使用操作系统内置的信任列表。以下命令将CA证书下载到web客户端并保存为文件:

1
curl -o my-ca.crt $VAULT_ADDR/v1/ca-root-x1/ca/pem # Linux/WSL和macOS
1
Invoke-WebRequest -Uri "$env:VAULT_ADDR/v1/ca-root-x1/ca/pem" -OutFile "my-ca.crt" # Windows

然后即可在浏览器导入,比如Firefox:

Firefox导入自签名CA

比如Safari:

Safari导入自签名CA

命令行:

同样,我们的根CA没有被操作系统信任,所以也是出错:

1
2
3
curl https://web-dev-01.lab.miyunda.com/
curl: (60) SSL certificate problem: self-signed certificate in certificate chain
More details here: https://curl.se/docs/sslcerts.html

我们将根CA证书放到指定的地方即可,这样也可以方便地加入到Chef或者Ansible:

Linux/WSL:

1
2
sudo cp my-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

注:以上只在Debian上试过,

macOS:

1
2
3
4
5
sudo security add-trusted-cert \
  -d \
  -r trustRoot \
  -k /Library/Keychains/System.keychain \
  my-ca.crt

注:有些app要使用自签名证书需要特别指定签发CA文件,无论是否被操作系统信任也要另外特别指定。


这样我们就给web服务器安装了我们自己的CA签发的证书,并且令客户端信任我们的CA。这种古法手作能用是能用,但是缺点很明显:

  1. 浪费人力
  2. 安装过程容易出错
  3. 证书过期了忘记更新/安装

好了,看过了就等于会了。下一篇我们将使用ACME协议实现数字证书的生命周期管理自动化。

0%