我在如何理解 Istio 中的 mTLS 流量加密这篇文章中提出流量加密的关键是证书管理。我们可以使用 Istio 中内置了 CA(证书授权机构)也可以使用自定义 CA 来管理网格内的证书。这篇博客将为你讲解 Istio 是如何进行证书管理的。
在介绍 Istio 的证书管理方式之前,我们先来了解一下什么是证书。若你已了解证书的作用及原理,请直接跳到 Istio 中的证书管理部分。
证书(Certificate),又称电子证书,是用于身份认证和加密通信的一种数字证明文件。在了解 Istio 的证书管理之前,我们先来了解一下什么是证书。如果你已经了解了证书,可以跳过这一节。
证书有很多类别,本文中的证书特指的是 X.509 V3 证书。X509 证书是一种常见的数字证书格式,用于在计算机网络中识别实体的身份。X509 是公钥基础设施(PKI)的国际标准,主要用于身份认证和信息加密,例如 TLS。X.509 证书中包含了个人、组织或计算机的身份信息和公钥。V3 是它的最新版本。它主要用于在客户端和服务器之间进行安全通信,例如在通过 HTTPS 访问网站时。x509 证书通常由 CA 颁发,该 CA 会验证实体的身份,并将这些信息编码到证书中。当客户端连接到服务器时,服务器会向客户端提供其 x509 证书,客户端会验证证书的有效性,并通过该证书来识别服务器的身份。通过这种方式,双方可以安全地进行通信,并确保数据传输的完整性和保密性。
谈到证书就不得不提哈希(Hash)函数,因为证书的内容会使用哈希函数进行哈希处理,然后用证书颁发者的私钥进行签名。这样,当收到一份证书时,接收者就可以使用证书颁发者的公钥来验证证书的合法性。
哈希函数是一种将任意长度的输入(也称为消息)映射为固定长度的输出的函数。这个输出也称为哈希值或消息摘要。
哈希函数有许多用途,其中一个重要的用途是密码存储。当用户在系统中设置密码时,通常不会将真实的密码直接存储在系统中。相反,会将密码进行哈希处理,并将哈希值存储在系统中。当用户登录时,系统会将用户输入的密码进行哈希处理,然后与存储的哈希值进行比较。如果两者相同,则证明用户输入的密码正确,反之则错误。
哈希函数有很多种类型,例如 MD5、SHA-1 等。这些函数都有一些共同的特点,比如输出固定长度、不可逆、散列冲突少等。
哈希函数的安全性与其输出的长度有关。一般来说,输出长度越长,哈希函数就越安全。但是,输出长度越长,哈希处理的时间就越长,因此要在安全性和效率之间进行平衡。
证书的用途广泛,凡是需要加密、认证、授权的场景都会用到它,比如:
证书就像是由权威机构印发的名片,供使用者表明其身份,同时还可以为信息加密,保证通信的安全性和完整性。下图展示的是 TLS 通信的大概步骤,其中证书承担了证明服务器身份和加密通信的职责。
下面以一个网站的 HTTP 链接为例,颁发数字证书、验证和加密通信的过程如下图所示。
详细步骤如下:
至此,双方建立了一个安全的通道,并可以通过该通道进行双向加密的数据传输。
你可以通过以下开源工具生成 X.509 证书:
因为可能大多数人都对 OpenSSL 比较熟悉,所以下文中我们将使用 OpenSSL 来创建证书。
下面以 X.509 V3 证书为例,讲解数字证书的组成。下面是该证书的一个示例:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
fc:c6:18:2e:20:bd:27:b5:6b:60:bc:47:23:6b:8b:d9
Signature Algorithm: sha256WithRSAEncryption
Issuer: O=cluster.local
Validity
Not Before: Dec 15 07:25:32 2022 GMT
Not After : Dec 16 07:27:32 2022 GMT
Subject:
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:eb:40:16:87:6c:17:5a:9c:b2:91:00:94:d1:31:
37:bb:d7:1e:e6:06:1c:a1:c1:35:64:54:82:54:af:
b8:4b:40:6f:e0:73:86:4e:c1:c6:75:b8:c8:30:ac:
69:16:e8:68:25:cb:dd:e8:53:55:ec:7a:bd:a9:d3:
42:44:7f:e5:f5:52:dd:99:ae:c2:1a:a2:06:1f:be:
1b:e6:3e:69:87:a3:fc:91:21:39:b0:a7:67:11:f2:
3c:55:c6:4b:04:15:1b:ff:49:14:88:c4:58:87:79:
96:5b:6e:00:1c:c1:e7:2c:53:0c:d1:77:dc:a8:82:
cc:fa:26:c1:bb:6c:df:a8:43:0c:b7:cc:f0:a2:11:
9b:e8:3f:8a:1d:ed:2a:ff:1f:d1:03:eb:8a:b9:98:
40:18:83:24:4f:14:95:a3:59:ef:67:0f:35:6d:ae:
91:81:b2:04:02:16:80:d1:39:bd:70:cf:0f:cb:9a:
81:39:d9:fe:52:a5:cf:79:4f:a3:69:d8:0d:39:6a:
48:24:8d:2b:88:04:fa:81:de:65:50:7d:1a:3d:cd:
f3:1c:42:63:29:75:a0:9b:8e:16:44:3a:89:d6:2b:
41:76:65:a5:2e:c8:b6:d2:89:42:5d:21:24:33:30:
f0:9d:0b:4d:cf:78:d5:45:2d:49:5a:55:50:98:93:
03:f5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
keyid:BA:31:8A:9C:ED:EB:49:D2:54:09:98:D9:4C:3A:9C:42:D0:64:8D:B2
X509v3 Subject Alternative Name: critical
URI:spiffe://cluster.local/ns/default/sa/httpbin
Signature Algorithm: sha256WithRSAEncryption
90:7f:cb:6f:0b:16:cb:59:7d:f4:87:a7:5a:38:fa:0a:16:d8:
83:0d:b1:36:77:a2:4a:fe:38:52:ab:49:e9:89:50:1a:4c:e9:
94:07:37:7f:27:bc:2c:ce:c1:d2:33:75:5d:b6:ab:ae:cb:2e:
71:f4:22:c0:40:15:27:02:75:c1:32:2e:83:49:73:6c:9a:ea:
04:ef:55:2d:8d:71:30:9b:e4:30:dd:95:20:0d:7c:d2:f4:30:
2f:07:2e:9f:53:37:e6:3d:14:c7:41:f4:09:8b:a3:76:56:c7:
c7:92:0f:fc:17:5a:5a:32:6c:9e:87:18:2e:51:75:54:68:d8:
01:c1:07:cc:b0:35:bf:0b:6c:62:a6:5b:23:61:35:c8:4f:7f:
e7:1f:a0:e9:11:44:a6:17:52:4d:00:40:21:de:63:ee:02:c8:
2b:5d:a1:7a:5d:7f:d5:d3:c1:7d:5f:00:40:e8:80:8d:cc:e9:
8a:c6:b4:98:fe:7a:7d:37:0c:6f:4c:31:91:7a:79:30:84:cd:
01:a7:14:f6:1b:33:8f:0f:50:1c:36:38:6b:24:da:cf:49:8a:
5b:28:cf:27:76:e1:a5:c7:e6:d5:6e:d8:36:85:aa:1f:a5:ac:
fa:f1:2e:a2:36:2e:25:b0:71:24:d1:3e:d5:e5:19:2b:0b:6f:
b7:17:e4:75
证书中各个字段的含义如下:
证书的验证需要通过证书信任链(Certificate Trust Chain)。证书信任链是指用于身份验证的一系列证书,它们形成一条从一个可信任的根证书颁发机构开始,逐级向下连接,直到用于验证某个特定证书的中间证书或终端证书的一种方式。证书信任链允许数字证书的可信度随着证书级别的升高而提高。
在下面的证书信任链示意图中,你可以看到四条信任链。
证书的信任链是一个树形结构,每个 CA 都可以有一或多个子 CA,一共有三种角色:
根 CA 是数字证书的最顶级颁发机构,因此它所颁发的证书是最可信的。根证书颁发机构通常由政府机构或其他权威机构(如国际基础设施安全组织)经营和监管。常见的根 CA 包括:
请注意,上述列表只是一个样例,实际上有许多其他根 CA。
在 Chrome 浏览器中打开一个 HTTPS 网页,你可以通过点击地址栏左侧的锁图标查看证书信息,其中包括证书信任链,例如 https://tetrate.io 的证书信任链如下图:
证书信任链允许客户端(例如,Web 浏览器)在验证终端证书时,逐级向上验证每个证书,以确定它是否可信。数字证书签发的原理是 CA 将证书拥有者的公钥与身份信息绑定在一起,然后 CA 使用其专有的私钥生成正式的数字签名,用以表示这个证书是经 CA 签发的。在证书校验时使用 CA 的公钥对这个证书上的数字签字进行验证即可。
在使用 Istio 之前,企业通常有自己的内部 PKI(公钥基础设施),那么如何将 Istio 纳入到 PKI 的证书信任链中呢?
我们知道 Istio 内置了证书管理功能,可以开箱即用,Istio 启动时会为 istiod 创建自签名证书,作为网格内所有工作负载的根证书。这样做有个问题,如果你有多网格,内置的根证书无法做到网格间互信。正确的做法是不使用 Istio 自签名证书,而是将 Istio 纳入到你的证书信任链中,将 Istio 集成到你的 PKI,为 PKI 每个网格创建一个中间证书,这样两个网格拥有了共同的信任根,就可以做到网格间互信。
通过为 Istio 网格创建中间 CA 使其纳入到企业内部 PKI 证书信任链中,如下图所示。
将 Istio 纳入企业内部 PKI 证书信任链后有诸多好处:
关于将 Istio 纳入企业内部 PKI 的证书信任链的详细说明请参考这篇博客。
默认情况下,Istio CA 会生成一个自签名的根证书和密钥,并使用它们来签署工作负载证书。为了保护根 CA 密钥,你应该使用在安全机器上离线运行的根 CA,并使用根 CA 向运行在每个集群上的 Istio CA 签发中间证书。Istio CA 可以使用管理员指定的证书和密钥来签署工作负载证书,并将管理员指定的根证书作为信任根分配给工作负载。
下图展示了 Istio 中的证书签发和挂载过程。
envoy
和 pilot-agent
。pilot-agent
为 Envoy 生成私钥,通过 UNIX Domain Socekt(UDS)使用 Secret Discovery Service(SDS)向 CA 发起证书签名请求(CSR),如果你没有配置 CA 插件的话,Istio 默认向 istiod 发起 CSR;istiod
内置 CA 向 pilot-agent
返回证书;pilot-agent
将生成的私钥和 CA 返回的证书发送给 envoy
挂载;Istio 默认使用内置于 istiod 中的 CA,也支持插入其他 CA,见 Istio 文档。若想使用自定义的 CA 证书和密钥为服务创建身份,你需要:
接下来,我们将以为 Bookinfo 的 productpage 服务创建和挂载证书为例详述 Istio 内置 CA 签发证书的流程。
Istio 启动时将创建一个自签名的 CA 证书,然后再用该 CA 证书为网格内的服务颁发证书。下面我们手动模拟 Istio 内置 CA 签发证书的步骤:
创建 CA 私钥 ca.key
;
openssl genrsa -out ca.key
创建 CA 配置文件 ca.conf
:
[ req ]
default_bits = 2048
prompt = no
utf8 = yes
encrypt_key = no
distinguished_name = req_dn
req_extensions = req_ext
x509_extensions = req_ext
[ req_dn ]
O = Istio
CN = Root CA
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, nonRepudiation, keyEncipherment, keyCertSign
使用 CA 私钥 ca.key
生成自签名证书 ca.pem
,其中主题中包含 CA 的信息:
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.pem -config ca.conf
PEM 文件是一种用于存储证书、公钥或私钥的文件。它采用 Base64 编码的 ASCII 格式,并使用特定的文件扩展名,例如 .pem
、.crt
、.cer
或 .key
。PEM 文件通常用于存储加密密钥、数字证书和公钥基础设施(PKI)证书。
PEM 文件的内容通常以一组特定的标头和脚本开始,例如 -----BEGIN RSA PRIVATE KEY-----
和 -----END RSA PRIVATE KEY-----
。这些标头和脚本指定了文件的类型和数据的开始和结束位置。
PEM 文件可以通过文本编辑器直接打开,但并不可读,因为它是由二进制编码格式 DER(可分辨编码规则)转化而来,要想解析它需要使用特别的工具,例如 OpenSSL。
为工作负载创建私钥 workload.key
:
openssl genrsa -out workload.key
创建证书签名请求配置文件 csr.conf
,其中包含 CA 的地址及附加信息;
[ req ]
default_bits = 2048
prompt = no
utf8 = yes
encrypt_key = no
distinguished_name = dn
req_extensions = req_ext
x509_extensions = req_ext
[ req_dn ]
O = Istio
CN = productpage
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, nonRepudiation, keyEncipherment, keyCertSign
基于工作负载的 CSR 配置文件 csr.conf
和工作负载的私钥文件 workload.key
创建证书签名请求 workload.csr
:
openssl req -new -key workload.key -out workload.csr -config csr.conf
基于 CA 的私钥 ca.key
、CA 的证书 ca.pem
和工作负载的证书签名请求创建服务器证书 workload.pem
:
openssl x509 -req -in workload.csr -CA ca.pem -CAkey ca.key \
-CAcreateserial -out workload.pem -days 365 \
-extensions req_ext -extfile csr.conf -sha256
Istiod 在收到工作负载的 CSR 后将根证书 ca.pem
和服务证书下发给工作负载;
查看工作负载中 Envoy 代理挂载的证书链:
istioctl proxy-config secret deployment/productpage-v1 -o json | jq -r \
'.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
chain.pem
文件中保存着 productpage
服务的证书链,因为我们使用的 Istio 内置 CA 作为根 CA,所以该文件中只保存有一个证书,可以运行下面的命令查看:
openssl x509 -noout -text -in chain.pem
查看 Envoy 代理挂载的根证书:
istioctl proxy-config secret deployment/productpage-v1 -o json | jq -r \
'.dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes' | base64 --decode > root.pem
root.pem
即为根证书,运行下面的命令查看:
openssl x509 -noout -text -in root.pem
root.pem
中的内容与 istiod-ca-cert
ConfigMap 中的 root-cert.pem
及 istio-ca-secret
中的 ca-cert.pem
是一样的,虽然现在 Envoy 已不在通过读取挂载卷来获得证书内容,但之所以保留了这些卷是为了向后兼容。
证书挂载到 Envoy 代理之后,istiod 将负责定期替换密钥证书,以及根据需要撤销密钥证书。
本文向你介绍了数字证书的作用、组成和证书信任链,以及 Istio 中内置的开箱即用的证书管理器运作的流程。但是 Istio 内置 CA 仍然有一定限制,在下一篇博客中我将向你介绍如何使用插件 SPIRE 和 cert-manager 来实现细粒度的证书管理和自动证书轮换。
最后更新于 2024/09/06