20.mTLS
1. 简介
两台主机通信的时候,如果是通过明文的方式通信两者之间的数据很容易被截获,两台主机要安全通信,需要在两者之间实现数据的加密。主要涉及到对称加密,非对称加密,哈希函数。
2. 对称加密
所谓对称加密,即加密和解密使用相同的密钥,这个密钥可以理解为就是密码。

这里A用一个对称加密密钥haha001加密了一个数据,然后把加密之后的数据发送给B之后,因为是加密数据,所以B是打不开的。所以A需要把密码告诉B才行。但是如何告诉B密钥是haha001呢?这是一个问题,因为这个过程很可能被别人监测到。
3. 非对称加密
对于非对称加密算法来说,包括2个密钥一个是公钥,一个是私钥。公钥是可以公开的,私钥需要保护好。对于非对称加密来说主要作用有两个,一是数据加密,而是数字签名。
3.1数据加密

上图里锁的图标表示公钥,钥匙的图标表示私钥。
- 第一步:B把公钥发送给A
- 第二步:A用B的公钥加密数据
- 第三步:A把加密后的数据发送给B
- 第四步:B用自己的私钥对加密数据进行解密
因为别人获取不到B的私钥,所以在第三步里即便数据被接获了也解密不了,因为只有B的私钥才能解密。
如果把对称加密和非对称加密结合使用的话,这样利用非对称加密就可以解决了前面对称加密算法中,对称加密私钥不方便传输的问题了。

- 第一步: B把公钥发送给A
- 第二步:A用B的公钥加密对称加密密钥haha001
- 第三步:A把加密后的密钥发送给B
- 第四步:B用自己的私钥解密A发送过来的数据,得到对称加密的密钥haha001
- 第五步:B用haha001解密A发送过来的对称加密数据
这样A用对称加密的数据发送给B之后,B也能顺利的打开了,这种方式看起来安全,但其实很容易受到中间人攻击,因为第一步里我们假设的是A获取的就是B的公钥,而不是别人冒充的。
下面我们看一下中间人攻击的过程,这里假设C是中间人

- 第一步:B把公钥发送给A,但C把原本发送给A的公钥截获了,此时C有了B的公钥。
- 第二步:C把自己的公钥发送给A,但是宣称是“B的公钥”,A不明真相,以为就是B的公钥
- 第三步:A用“B的公钥”(其实是C的公钥)加密对称加密的密钥
- 第四步:把加密后的对称加密的密钥发送给B,但是这个又被C截获了,因为实际用的是C的公钥加密的,所以C用自己的私钥是能够解密的。此时C获取了对称加密的密钥haha001
- 第五步:C用B的公钥加密对称加密密钥haha001,之后发送给B
- 第六步:B用自己的私钥解密数据,得到对称密钥haha001
- 第七步:A把用对称加密后的护具发送给B,但也被C截获了,因为C知道了对称加密密钥,所以C是能看到数据里的内容并做修改的。
- 第八步:C再次用对称密钥haha001加密数据之后转发给B
- 第九步:B用对称密钥haha001解密数据
整个过程A和B都以为他们是直接通信的,殊不知这中间所有的数据都被C看到了,这就是中间人攻击。
那么如何解决这个问题呢?我们先了解数字签名。
4. 数字签名
数字签名是私钥加密数据,公钥解密数据。

- 第一步:B先把公钥发送给A
- 第二步:B然后用哈希函数对所要传输的数据求的哈希值hash1,哈希函数的特点是输入不定长的值总是得到定长的值,比如:
1 | root@vms61:~# wc -c /etc/hosts |
- 第三步:B会用自己的私钥对哈希值hash1进行加密
- 第四步:B把原始数据和加密后的哈希值发送给A
- 第五步:A先用B的公钥把收到的加密后的哈希值hash1解密,得到hash1,这个hash1和第2步生成hash1是一样的。
- 第六步:B会对收到的数据data求得哈希值hash2
- 第七步:B对比hash1和hash2来判断data在传输过程中是不是被修改过。如果两个hash值是一样的,就说明数据data在传输过程中是没有被修改的,如果两个哈希值不一样说明数据传输过程中被修改过。
这里会带来两个问题:
- 第一:这里也会遇到中间人攻击的问题,即第一步的公钥被C截获了,然后把自己的公钥发送给了A。在第四步里,数据data和hash1被C截获,然后C修改了data的数据,然后求得哈希值之后用自己的私钥做数据签名。其实所有的中间人攻击的根本在于此。
- 第二:即使没有中间人攻击,B的密钥对跟B这个主体之间没有必然的联系,因为B可以随时删除掉自己的密钥对,然后重新生成。
5. 证书中心
在互联网上存在一种权威机构叫做证书中心(简称CA),一个前提就是我们都要信任CA。

前面讲中间人攻击的主要原因就是A获取B的公钥可能是假冒的,所以A不会信任别人发给他的公钥,且B也知道他直接把他自己生成的公钥发送给别人,别人也不信任,所以B不会再生成私钥了。
- 第一步:B会用自己的私钥生成一个证书请求文件(类似于申请书)
- 第二步:B把证书请求文件发送到CA去申请证书。
- 第三步:CA会审核B的身份,之后会颁发证书给B,这个证书其实就是公钥,只是上面有了CA的数字签名,以证明这个证书是CA颁发的。这一步解决了”数字签名“部分B和他的密钥对之间每有必然联系的问题,因为这里有CA来证明这个密钥对就是B的,B不能抵赖。
- 第四步:B会把证书发送给A,说这是我的证书并且上面有CA的数字签名,不会被别人伪冒。
- 第五步:A是持怀疑态度的,到底是不是真的由CA颁发的,还是别人伪冒的呢?所以A要验证这个证书的真伪性。此时A需要CA的公钥(像浏览器里都内置了权威CA的公钥),然后会用权威CA的公钥验证B证书的公钥上的数字签名。
之后,A会用B的证书加密对称加密算法的密钥发送给B,B用私钥解密,这样A和B就可以安全的传输数据了,整个过程叫做TLS(传输层安全)
这里只有A验证了B的证书合法性,所以叫做单向TLS,如果A也有自己的私钥及CA颁发的证书,那么除了A要验证B证书的合法性之外,B也要验证A证书的合法性,即两边互相验证,这个就叫做mTLS(mutual TLS,双向TLS)了。
6. k8s里的mTLS

kubeadm方式部署,创建2个CA中心,kubernetes组件一个,etcd组件一个。组件签发证书为1年,CA证书为10年。
6.1 验证tls
1 | openssl rand -hex 10 |
7. cfssl工具签发私有证书
下载地址
1 | curl -OL https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 |
修改文件名权限
1 | for i in * ; do n=${i%_*} ; mv $i $n; done ; chmod +x |
7.1 概念
ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;
signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;
server auth:表示client可以用该 CA 对server提供的证书进行验证;
client auth:表示server可以用该CA对client提供的证书进行验证;
CN: Common Name,浏览器使用该字段验证网站是否合法,一般写的是域名。
C: Country, 国家
L: Locality,地区,城市
ST: State,州,省
O: Organization Name,组织名称,公司名称
OU: Organization Unit Name,组织单位名称,公司部门
7.2 生成ca配置文件
1 | cfssl print-defaults config > ca-config.json |
ca-config.json
1 | { |
7.3 生成证书请求文件配置
1 | cfssl print-defaults csr > ca-csr.json |
root@vms41:~/CA# cat ca-csr.json
1 | { |
7.4 生成自签名证书
1 | cfssl gencert -initca ca-csr.json | cfssljson -bare ca |
1 | root@vms41:~/CA# ll |
7.5 生成用户证书请求文件
1 | cfssl print-defaults csr > client-csr.json |
1 | { |
7.6 签发client证书
1 | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www client-csr.json| cfssljson -bare client |
1 | root@vms41:~/CA# ll |
8. cert-manager

官方文档:https://letsencrypt.org/zh-cn/docs/
运行方式:https://letsencrypt.org/zh-cn/how-it-works/
安装文档:https://letsencrypt.org/zh-cn/how-it-works/
8.1 创建
1 | kubectl apply -f cert-manager.yaml |
1 | root@vms40:~/yaml/cert-manager# kubectl -n cert-manager get all |
8.2 创建clusterIssuer
创建secret
dns的token
1 | apiVersion: v1 |
8.3 创建clusterissue
1 | apiVersion: cert-manager.io/v1alpha2 |
8.3 申请证书
1 | kubectl apply -f certificate.yaml |
1 | apiVersion: cert-manager.io/v1alpha2 |
查看证书申请
1 | root@vms40:~/yaml/cert-manager# kubectl get certificaterequests.cert-manager.io |
查看签发状态
1 | root@vms40:~/yaml/cert-manager# kubectl get challenges.acme.cert-manager.io |
查看证书
1 | root@vms40:~/yaml/cert-manager# kubectl get certificate |
修改ingress使用签发的证书
1 | apiVersion: networking.k8s.io/v1 |
自动申请证书
创建ingress自动去ClusterIssuer申请证书
1 | apiVersion: extensions/v1beta1 |
8.4 使用自签名CA
8.4.1 创建secret
把CA的证书和密钥写入到 secre
1 | kubectl create secret tls ca-key --cert=ca.pem --key=ca-key.pem --namespace=cert-manager |
8.4.2 创建clusterissuer
用自己的CA模拟签发机构
1 | apiVersion: cert-manager.io/v1alpha2 |
8.4.3 创建ingress
ingress中指定签发机构
1 | apiVersion: extensions/v1beta1 |