阅读本篇文章需要先完成上一篇:搭建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:
比如Safari:
命令行:
同样,我们的根CA没有被操作系统信任,所以也是出错:
1
2
3
| curl https://web-dev-01.lab.miyunda.net/
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。这种古法手作能用是能用,但是缺点很明显:
- 浪费人力
- 安装过程容易出错
- 证书过期了忘记更新/安装
好了,看过了就等于会了。下一篇我们将使用ACME协议实现数字证书的生命周期管理自动化。