API 网关是 API 全生命周期管理中的关键基础组件,是所有终端流量的入口,负责把下游客户端的 API 请求路由到正确的上游服务进行处理。因此,API 网关承担了上游服务和下游客户端之间的网络通信。
Apache APISIX 作为新一代的云原生 API 网关,提供了下游客户端与 APISIX、APISIX 与上游服务之间的 TLS/mTLS 通信机制,从而保证下游客户端与 API 网关之间、API 网关与上游服务之间的网络通信安全。APISIX 将SSL 证书保存为 SSL Certificate 对象,并通过支持 TLS 协议的扩展 SNI 实现 SSL 证书的动态加载。
为了更好地对 APISIX 中 SSL 证书安全存储,APISIX 实现了与 HashiCorp Vault 的集成,从而借助 Vault 的 secret 安全存储优势,实现对 SSL 证书的统一管理。本文以配置下游客户端与 APISIX 之间 HTTPS 通信为例,介绍 APISIX 如何集成 Vault 实现 SSL 证书管理。
什么是 SSL 证书
SSL/TLS 是一种安全通信协议,它通过建立通信双方的加密网络连接,从而保护网络通信的安全性。SSL/TLS 协议通过认证用户和服务器,确保数据发送到正确的客户机和服务器。此外,SSL/TLS 协议可以加密通信数据,从而确保数据在传输过程中不被窃取、篡改或伪造。
SSL 证书是一种数字证书,用于认证网站的身份,并使用 SSL/TLS 协议对网络通信进行加密。SSL 证书通常由受信任的数字证书颁发机构 CA 颁发,其主要包含以下信息:
- 证书颁发机构的域名
- 证书颁发机构
- 证书颁发机构的数字签名
- 关联的子域
- 证书颁发日期
- 证书到期日期
- 公钥(私钥为保密状态)
什么是 HashiCorp Vault
HashiCorp Vault(以下简称 Vault)是一款企业级 Secret 管理工具,可以存储和管理令牌、密码、证书等敏感数据。Vault 可以与整个IT系统中的技术进行集成,提供基于身份的安全自动化和加密服务,集中控制对敏感数据和系统的访问,帮助组织降低数据泄露和数据暴露的风险,从而提高云和应用程序的安全性。
如何在 Vault 中存储 APISIX SSL 证书
环境准备
- 安装 Docker
- 安装 cURL
- 一个正常运行的 APISIX 服务,或按照 Getting Started tutorial 部署一个 APISIX Docker 容器
部署并配置 Vault 服务
本节将使用 Docker 部署一个 Vault 容器服务。如果环境中已有可用的 Vault 服务实例,可跳过本节。
创建并部署一个 Dev 模式下的 Vault 容器,命名为 apisix-quickstart-vault
。指定 Vault Token 为 apisix-quickstart-vault-token
并将端口 8200
映射至主机:
1docker run -d --cap-add=IPC_LOCK \
2 -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' \
3 -e 'VAULT_ADDR=http://0.0.0.0:8200' \
4 -e 'VAULT_DEV_ROOT_TOKEN_ID=apisix-quickstart-vault-token' \
5 -e 'VAULT_TOKEN=apisix-quickstart-vault-token' \
6 --network=apisix-quickstart-net \
7 --name apisix-quickstart-vault \
8 -p 8200:8200 vault:1.13.0
选择 kv
作为 APISIX 的 SSL 证书存储路径:
1docker exec apisix-quickstart-vault vault secrets enable -path=kv -version=1 kv
配置 APISIX
APISIX 需要从 Vault 读取 SSL 证书,因此 Vault 应授予 APISIX 指定路径的读权限。
创建一个名为 apisix-policy.hcl
的 Vault 策略文件,授予 APISIX 对路径 kv/apisix/
的读权限:
1docker exec apisix-quickstart-vault /bin/sh -c "echo '
2path \"kv/apisix/*\" {
3 capabilities = [\"read\"]
4}
5' > /etc/apisix-policy.hcl"
将创建好的策略文件 apisix-policy.hcl
应用至 Vault:
1docker exec apisix-quickstart-vault vault policy write apisix-policy /etc/apisix-policy.hcl
创建一个 id 为 quickstart-secret-id
的 APISIX secret 对象,保存 Vault 连接信息和证书存储路径:
1curl -i "http://127.0.0.1:9180/apisix/admin/secrets/vault/quickstart-secret-id" -X PUT -d '
2{
3 "uri": "http://apisix-quickstart-vault:8200",
4 "prefix": "kv/apisix",
5 "token" : "apisix-quickstart-vault-token"
6}'
存储 SSL 证书至 Vault
创建自签 CA 证书 ca.crt
和密钥 ca.key
:
1openssl genrsa -out ca.key 2048 && \
2 openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CN=ROOTCA" && \
3 openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt
通过 CA 签发 SSL 证书 server.crt
及密钥 server.key
,其 common name (CN) 为 test.com
:
1openssl genrsa -out server.key 2048 && \
2 openssl req -new -sha256 -key server.key -out server.csr -subj "/CN=test.com" && \
3 openssl x509 -req -days 36500 -sha256 -extensions v3_req \
4 -CA ca.crt -CAkey ca.key -CAserial ca.srl -CAcreateserial \
5 -in server.csr -out server.crt
将签发的 SSL 证书及密钥拷贝至 Vault 容器中:
1docker cp server.key apisix-quickstart-vault:/root/
2docker cp server.crt apisix-quickstart-vault:/root/
使用 vault kv put
命令,将 SSL证书及密钥存储为 secret,其 key 为 ssl
,存储路径为 kv/apisix
:
1docker exec apisix-quickstart-vault vault kv put kv/apisix/ssl test.com.crt=@/root/server.crt test.com.key=@/root/server.key
通过上述命令,我们在 Vault 中存储了一个名为 ssl
的 secret,其包含 2 个键值对:证书及私钥。
如何使用 Vault 中存储的 APISIX SSL 证书
APISIX 支持下游客户端与 APISIX、APISIX 与上游服务之间的 TLS/mTLS 网络通信加密,Vault 存储的 SSL 证书均可使用。本文以配置客户端与 APISIX 之间 HTTPS 通信为例,演示如何在 APISIX 中使用 Vault 存储的 SSL 证书。
配置客户端与 APISIX 之间 HTTPS 通信
创建一个 SSL certificate 对象来保存 SSL 证书:
1curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT -d '
2{
3 "id": "quickstart-tls-client-ssl",
4 "sni": "test.com",
5 "cert": "$secret://vault/quickstart-secret-id/ssl/test.com.crt",
6 "key": "$secret://vault/quickstart-secret-id/ssl/test.com.key"
7}'
该对象的 sni 为 test.com
,与签发证书的 CN 保持一致。cert 和 key 对应为签发的证书及私钥,通过既定的 secret 资源定位符从 Vault 中自动获取,其资源定位规则为:
1$secret://$manager/$id/$secret_name/$key
- manager: 密钥管理服务 Vault
- id: APISIX secret 资源 ID
- secret_name: Vault 中的 secret 名称
- key:名为 secret_name 的 secret 中键值对的 key
验证客户端与 APISIX 之间 HTTPS 通信
创建一个路由,将所有发送至 /ip
的请求转发至上游 httpbin.org
:
1curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
2{
3 "id": "quickstart-client-ip",
4 "uri": "/ip",
5 "upstream": {
6 "nodes": {
7 "httpbin.org:80":1
8 },
9 "type": "roundrobin"
10 }
11}'
使用 cURL 发送请求至 https://test.com:9443/ip
,test.com
可解析为 127.0.0.1
:
1curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip"
如果配置成功,cURL 返回的客户端与 APISIX TLS 握手过程将与以下结果相同:
1* Added test.com:9443:127.0.0.1 to DNS cache
2* Hostname test.com was found in DNS cache
3* Trying 127.0.0.1:9443...
4* Connected to test.com (127.0.0.1) port 9443 (#0)
5* ALPN, offering h2
6* ALPN, offering http/1.1
7* successfully set certificate verify locations:
8* CAfile: /etc/ssl/certs/ca-certificates.crt
9* CApath: /etc/ssl/certs
10* TLSv1.3 (OUT), TLS handshake, Client hello (1):
11* TLSv1.3 (IN), TLS handshake, Server hello (2):
12* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
13* TLSv1.3 (IN), TLS handshake, Certificate (11):
14* TLSv1.3 (IN), TLS handshake, CERT verify (15):
15* TLSv1.3 (IN), TLS handshake, Finished (20):
16* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
17* TLSv1.3 (OUT), TLS handshake, Finished (20):
18* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
19* ALPN, server accepted to use h2
20* Server certificate:
21* subject: CN=test.com
22* start date: Apr 21 07:47:54 2023 GMT
23* expire date: Mar 28 07:47:54 2123 GMT
24* issuer: CN=ROOTCA
25* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
26* Using HTTP2, server supports multi-use
27* Connection state changed (HTTP/2 confirmed)
28* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
29* Using Stream ID: 1 (easy handle 0x556274d632e0)
30> GET /ip HTTP/2
31> Host: test.com:9443
32> user-agent: curl/7.74.0
33> accept: */*
34>
35* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
36* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
37* old SSL session ID is stale, removing
38* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
39< HTTP/2 200
40HTTP/2 200
41...
总结
本文介绍了 APISIX 如何集成 Vault 实现 SSL 证书管理,并以配置下游客户端与 APISIX 之间 HTTPS 通信为例,详细展示了配置与集成步骤。关于 APISIX 中 SSL 证书的相关概念及使用场景,可进一步参考以下文章: