1、Kubernetes 认证方式
Kubernetes集群的访问权限控制由API Server负责,API Server的访问权限控制由身份验证(Authentication)、授权(Authorization)和准入控制(Admission control)三个步骤组成,这个三个步骤是按序进行的(详细介绍请参见《(转)使用kubectl访问Kubernetes集群时的身份验证和授权》)。
其中身份验证这个环节它面对的输入是整个http request,它负责对来自client的请求进行身份校验,支持的方法包括:
- CA 认证,基于CA根证书签名的双向数字证书认证
- Token认证,通过Token识别每个合法的用户
- Basic认证
API Server启动时,可以指定一种Authentication方法,也可以指定多种方法。如果指定了多种方法,那么APIServer将会逐个使用这些方法对客户端请求进行验证,只要请求数据通过其中一种方法的验证,API Server就会认为Authentication成功;在较新版本kubeadm引导启动的k8s集群的API Server初始配置中,默认支持CA认证和Token认证两种身份验证方式。在这个环节,API Server会通过client证书或http header中的字段(比如ServiceAccount的JWTToken)来识别出请求的“用户身份”,包括”user”、”group”等,这些信息将在后面的授权和准入控制环节用到。
在Kubernetes中,Kubectl和API Server、Kubelet和API Server、API Server和Etcd、Kube-Scheduler和API Server、Kube-Controller-Manager和API Server以及Kube-Proxy和API Server之间是基于CA根证书签名的双向数字证书方式进行认证,此方式是最为严格和安全的集群安全配置方式,也是我们本文介绍的主角;在Kubernetes中,集成的组件和API Server之间也可以选择配置基于CA根证书签名的双向数字证书方式进行认证,比如Metrics Servser;在Kubernetes中,Pod和API Server之间如果没有配置基于CA根证书签名的双向数字证书方式进行认证的话,则默认通过Token方式(ServiceAccount的JWTToken))进行认证。
2、Kubernetes CA 认证涉及相关知识
在详细介绍Kubernetes CA认证之前,我们先简述下和Kubernetes CA认证相关的知识。
2.1 CA证书相关知识
- 对称加密:指加密与解密使用同一密钥的方式,速度快,但密钥管理困难。
- 非对称加密:指加密和解密使用不同密钥的方式,速度慢。公钥和私钥匙一一对应的,一对公钥和私钥统称为密钥对。由公钥进行加密的密文,必须使用与该公钥配对的私钥才能解密。密钥对中的两个密钥之间具有非常密切的关系——数学上关系——公钥和私钥匙不能分布单独生成的。它有两种用途:(1)加密传输过程:公钥加密,私钥解密;(2)签名过程:私钥加密,公钥解密。
- 混合加密:将对称密钥与非对称密钥结合起来,这种系统结合了两者的优势。比如,SSL/TLS使用混合加密(Hybrid Encryption)的方式来保证通信的安全性,在混合加密中,使用非对称加密算法来协商对称密钥,然后使用对称加密算法来对通信过程中的数据进行加密和解密,以提供更高的安全性和效率。
- 数字签名:数字签名是一种用于确保数字信息的完整性、身份认证和不可抵赖性的加密技术。数字签名是基于公钥加密和非对称密钥技术实现的,常被用于验证数字文档、软件、电子邮件等的真实性和完整性。数字签名的基本原理是将原始数据通过哈希函数(Hash Function)生成一个摘要(Digest),然后使用发送者的私钥对摘要进行加密,生成数字签名。接着,将原始数据和数字签名一起传输给接收者。接收者收到数据后,使用发送者的公钥对数字签名进行解密,得到摘要。然后,接收者对接收到的原始数据使用相同的哈希函数生成另一个摘要,将两个摘要进行比较,如果两个摘要一致,则表明原始数据没有被篡改过,数字签名也是合法的,否则就表明原始数据已经被篡改过或者数字签名不合法。要正确的使用数字签名,有一个大前提,那就是用于验证签名的公钥必须属于真正的发送者。
- 证书:数字证书是基于公钥加密和非对称密钥技术实现的,通过数字证书可以验证一个数字实体的身份信息,简单来说证书就是为公钥加上数字签名。它是由数字证书颁发机构(CA,Certificate Authority)签发的一种数字文件,包含了证书持有者的身份信息和公钥等关键信息。数字证书通常包含以下信息:
- 证书颁发机构的名称和公钥。
- 证书持有者的名称、电子邮件地址和公钥等身份信息。
- 证书有效期限和用途。
- 证书颁发机构的数字签名。
- CA(证书颁发机构):CA是一个机构,专门为其他人签发证书,这个证书保存其他人的公钥,确保了公钥的来源且没有被篡改。CA本身有自己的公私钥对,私钥用于签发其他证书,公钥用于验证证书,CA公钥同样需要保护,这就是CA证书。那么CA证书是谁签发呢,从签名的原理来看,必然存在CA自己给自己签名,这就是根CA证书。根CA是非常宝贵的,通常出于安全的考虑会签发一些中间CA证书,然后由中间CA签发最终用户证书,这样就构成了一个信任链。接收者信任某个CA证书,那么由此CA签发的证书就都被信任。公信的根CA全球只有有限的一些,它们通过第三方机构审计,具有权威性和公正性,通常操作系统或浏览器已经内置安装,由这些根CA签发的证书都会被信任。用户也可以自行安装信任的证书,其风险需要用户自己承担,一定要确保证书来源可靠。
- 根证书(自签名证书):根证书是CA认证中心给自己颁发的证书,是信任链的起始点。
2.2 HTTPS双向认证流程
Kubernetes CA认证也叫HTTPS证书认证,执行ApiServer CA认证过滤器链逻辑的前提是客户端和服务端完成HTTPS双向认证,下面着重说下HTTPS双向认证流程:
1.客户端发起建⽴HTTPS连接请求,将SSL协议版本的信息发送给服务端;
2.服务器端将本机的公钥证书(server.crt)发送给客户端;
3. 客户端通过自己的根证书(ca.crt)验证服务端的公钥证书(server.crt)的合法性(包括检查数字签名,验证证书链,检查证书的有效期 ,检查证书的撤回状态),取出服务端公钥。
4. 客户端将客户端公钥证书(client.crt)发送给服务器端;
5. 服务器端使⽤根证书(ca.crt)解密客户端公钥证书,拿到客户端公钥;
6. 客户端发送⾃⼰⽀持的加密⽅案给服务器端;
7. 服务器端根据⾃⼰和客户端的能⼒,选择⼀个双⽅都能接受的加密⽅案,使⽤客户端的公钥加密后发送给客户端;
8. 客户端使⽤⾃⼰的私钥解密加密⽅案,⽣成⼀个随机数R,使⽤服务器公钥加密后传给服务器端;
9. 服务端⽤⾃⼰的私钥去解密这个密⽂,得到了密钥R;
10. 服务端和客户端在后续通讯过程中就使⽤这个密钥R进⾏通信了。
注意:默认情况下,HTTPS是先进行TCP三次握手,再进行TLS四次握手。
3、Kubernetes 基于CA根证书签名的双向数字证书认证
下面以Kubectl(客户端)和API Server(服务端)认证为例,讲解基于CA根证书签名的双向数字证书认证。
3.1 API Server证书配置
使用Kubeadm初始化的Kubernetes集群中,API Server是以静态Pod的形式运行在Master Node上。 可以在Master Node上找到其定义文件/etc/kubernetes/manifests/kube-apiserver.yaml,其中启动命令参数部分如下:
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 |
|
注意:"API Server" 和 "kube-apiserver" 可以视为同义词,都是 Kubernetes 中核心的 API 处理器,但 "kube-apiserver" 是 Kubernetes 中默认的 API Server 实现。
API Server作为服务端时,我们注意到有如下三个启动参数:
- --client-ca-file: 指定CA根证书文件为/etc/kubernetes/pki/ca.crt,内置CA公钥用于验证某证书是否是CA签发的证书,Kubectl和Kube-Apiserver之间认证的话,ca.crt用于验证Kubectl的客户端证书是否是CA签发的证书。
- --tls-cert-file:指定Kube-Apiserver证书文件为/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file: 指定Kube-Apiserver私钥文件为/etc/kubernetes/pki/apiserver.key
在Master Node上进入/etc/kubernetes/pki/目录:
1 2 3 4 5 |
|
查看CA根证书ca.crt:
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 50 51 52 53 54 55 56 57 |
|
注意:查看证书的方式有很多,不只可以通过openssl工具,也可以通过在线SSL网站解析证书,比如:SSLeye。
验证CA根证书ca.crt证书的合法性:
1 2 |
|
注意:我们知道验证证书合法性,就是用公钥验证证书的数字签名,由于CA根证书是自签名证书,公钥和数字签名信息都在ca.crt证书文件中,所以用以上命令验证ca.crt证书的合法性即可。
查看ApiServer的证书apiserver.crt:
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 |
|
验证apiserver.crt由ca.crt签发:
1 2 |
|
3.2 生成Kubectl客户端私钥和证书
客户端要通过HTTPS证书双向认证的形式访问ApiServer需要生成客户端的私钥和证书,其中客户端证书的在生成时-CA参数要指定为ApiServer的CA根证书文件/etc/kubernetes/pki/ca.crt,-CAkey参数要指定为Api Server的CA key /etc/kubernetes/pki/ca.key。
下面生成客户端私钥和证书:
1 2 3 4 5 6 7 |
|
注意 1:在 X.509 数字证书中,Subject 字段是用于表示证书拥有者的字段之一,通常包含多个子字段,用于描述证书拥有者的不同属性。下面是 Subject 字段中常见的子字段以及它们的含义:
C (Country): 表示证书拥有者所在的国家或地区的 ISO 3166-1 代码。
ST (State or Province): 表示证书拥有者所在的州或省份的全名或简称。
L (Locality): 表示证书拥有者所在的城市或城镇的名称。
O (Organization Name): 表示证书拥有者的组织名称。
OU (Organizational Unit Name): 表示证书拥有者的组织中的部门或单位名称。
CN (Common Name): 表示证书拥有者的通用名称,通常是证书关联的域名。
Email: 表示证书拥有者的电子邮件地址。
除了上述常见的子字段外,Subject 字段还可以包含其他自定义的子字段,用于描述证书拥有者的其他属性。需要注意的是,Subject 字段中的属性并非必须全部存在,具体哪些属性需要包含取决于证书颁发机构的要求,在生成Kubectl客户端证书签名请求文件时,只是指定了证书拥有者的CN和O属性,分别代表k8s用户和组。本示例中,Kubectl客户端基于https双向认证方式与Kube-Apiserver服务端建立连接后,进入Kube-Apiserver认证过滤器链,首先进入CA认证过滤器(客户端证书不为空才会进入CA认证过滤器链,而本示例讲解的是基于CA证书的双向认证方式,客户端证书自然不为空),Kube-Apiserver服务端通过自己的根证书ca.crt解析Kubectl客户端证书,获取Kubectl客户端证书拥有者的CN和O属性,然后生成User结构体对象。
1
2
3
4
User: &user.DefaultInfo{
Name: chain[0].Subject.CommonName, //证书CN属性值
Groups: chain[0].Subject.Organization, //证书O属性值
}
Kube-Apiserver服务端能够通过自己的根证书ca.crt解析Kubectl客户端证书并生成User结构体对象的话,则代表用户认证成功,不再执行其他认证方式(Token认证),之后进入Kube-Apiserver授权阶段,授权的话遍历rolebinding/clusterrolebinding,比对User结构体对象和rolebinding/clusterrolebinding中的subjects找到用户或组对应的role/clusterrole,进而确定kubectl客户端在k8s集群中的角色。
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
// kubernetes-1.21.5/pkg/registry/rbac/validation/rule.go
func
appliesToUser(user user.Info, subject rbacv1.Subject, namespace string) bool {
switch
subject.Kind {
// rolebinding/clusterrolebinding中的subject类型是User类型,则比对用户对象名
case
rbacv1.UserKind:
return
user.GetName() == subject.Name
// rolebinding/clusterrolebinding中的subject类型是Group类型,则比对用户对象组
case
rbacv1.GroupKind:
return
has(user.GetGroups(), subject.Name)
case
rbacv1.ServiceAccountKind:
// default the namespace to namespace we're working in if its available. This allows rolebindings that reference
// SAs in th local namespace to avoid having to qualify them.
saNamespace := namespace
if
len(subject.Namespace) > 0 {
saNamespace = subject.Namespace
}
if
len(saNamespace) == 0 {
return
false
}
// use a more efficient comparison for RBAC checking
return
serviceaccount.MatchesUsername(saNamespace, subject.Name, user.GetName())
default
:
return
false
}
}
注意 2:.srl 是 OpenSSL 工具生成 X.509数字证书时自动生成的一个文件,用于记录证书的序列号。在生成证书时,每个证书都会被分配一个唯一的序列号,该序列号会被包含在证书中,并且存储在 .srl 文件中。由于 .srl 文件仅包含证书的序列号,因此通常可以安全地删除该文件,而不会影响现有的证书。
注意3:Kube-Apiserver tls客户端认证配置为RequestClientCert(客户端请求可以不发送客户端证书)。
1
2
3
4
5
6
// staging/src/k8s.io/apiserver/pkg/server/secure_serving.go:45
if
s.ClientCA != nil {
// Populate PeerCertificates in requests, but don't reject connections without certificates
// This allows certificates to be validated by authenticators, while still allowing other auth types
tlsConfig.ClientAuth = tls.RequestClientCert
}
即可以不使用 SSL/TLS 加密方式、或仅使用 SSL/TLS 单向认证方式或使用 SSL/TLS 双向认证方式与Kube-Apiserver服务端建立连接,只有客户端证书不为空,才会执行CA认证过滤器链逻辑。
1
2
3
4
if
config.ClientCAContentProvider != nil {
certAuth := x509.NewDynamic(config.ClientCAContentProvider.VerifyOptions, x509.CommonNameUserConversion)
authenticators = append(authenticators, certAuth)
}
查看生成的kubectl客户端证书client.crt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
验证kubectl客户端证书client.crt是由ca.crt签发:
1 2 |
|
3.3 使用生成的Kubectl客户端私钥和证书访问ApiServer
1 2 3 4 5 6 7 8 |
|
注意 1:如果执行kubectl客户端命令报如下错误:请通过以下命令查看 kubectl 是否之前加入过别的 k8s 集群:
1
2
3
4
5
6
7
8
[root@node1 pki]# kubectl --server=https://10.20.30.31:6443 \
> --certificate-authority=ca.crt \
> --client-certificate=client.crt \
> --client-key=client.key \
> get nodes
Error in configuration:
* client-cert-data and client-cert are both specified for kubernetes-admin. client-cert-data will override.
* client-key-data and client-key are both specified for kubernetes-admin; client-key-data will override
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@node1 pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.20.30.31:6443
name: cluster.local
contexts:
- context:
cluster: cluster.local
user: kubernetes-admin
name: kubernetes-admin@cluster.local
current-context: kubernetes-admin@cluster.local
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
在问题节点执行如下命令,用于清空 kubectl 的配置(或者一般情况下直接删除/root/.kube/config文件即可),执行完以下命令后再执行kubectl命令便不会再报此错误。
1
2
3
$ /usr/bin/kubectl config unset users
$ /usr/bin/kubectl config unset clusters
$ /usr/bin/kubectl config unset contexts
注意 2:本文主要讲解基于CA证书的双向认证方式,如果执行kubectl客户端命令报cannot list resource "nodes" in API错误,请检查kubectl客户端证书拥有者在k8s集群中的角色是否拥有访问node资源权限。
4、总结
在Kubernetes中,Kubectl和API Server、Kubelet和API Server、API Server和Etcd、Kube-Scheduler和API Server、Kube-Controller-Manager和API Server以及Kube-Proxy和API Server之间是基于CA根证书签名的双向数字证书方式进行认证;在Kubernetes中,集成的组件和API Server之间也可以选择配置基于CA根证书签名的双向数字证书方式进行认证,比如Metrics Servser。
Kubernetes组件之间使用基于CA证书的双向认证方式可以带来以下好处:
-
更高的安全性:双向认证可以确保客户端和服务器之间的通信是双向加密的,从而提高了通信的安全性,减少了数据泄露和中间人攻击等风险。
-
认证客户端身份:使用双向认证可以让服务器验证客户端的身份,并且只有被授权的客户端才能访问服务器,从而减少了恶意攻击和未经授权的访问。
-
降低攻击风险:在双向认证中,服务器会要求客户端提供证书,这样可以避免一些恶意攻击,比如伪造证书的攻击等。
-
确保数据完整性:双向认证可以确保客户端和服务器之间的通信是完整的,没有被篡改或修改过的数据。
总之,双向认证可以提供更高的安全性和保护,减少了攻击风险,同时确保了数据的完整性和保密性,因此在 Kubernetes 中使用双向认证是一种非常有效的安全措施。
注意 1:在 Kubernetes 官方手册中给出了 ”用户“ 的概念,Kubernetes 集群中存在的用户包括 ”普通用户“ 与 “service account” 但是 Kubernetes 没有普通用户的管理方式,只是将使用集群的证书 CA 签署的有效证书的用户都被视为合法用户。
注意 2: 对于CA双向认证方式,Kubectl客户端与Kube-Apiserver服务端完成三次握手和HTTPS双向认证后,进入Kube-Apiserver认证过滤器链,首先进入CA认证过滤器,Kube-Apiserver服务端通过自己的根证书ca.crt解析Kubectl客户端证书,获取Kubectl客户端证书拥有者的CN和O属性,然后生成User结构体对象。Kube-Apiserver服务端能够通过自己的根证书ca.crt解析Kubectl客户端证书并生成User结构体对象的话,则代表用户认证成功,不再执行其他认证方式(Token认证),之后进入Kube-Apiserver授权阶段,授权的话遍历rolebinding/clusterrolebinding,比对User结构体对象和rolebinding/clusterrolebinding中的subjects找到用户或组对应的role/clusterrole,进而确定kubectl客户端在k8s集群中的角色。
注意 3:Kube-Apiserver tls客户端认证配置为RequestClientCert(客户端请求可以不发送客户端证书),即可以不使用SSL/TLS加密方式或仅使用SSL/TLS单向认证方式或使SSL/TLS双向认证方式与Kube-Apiserver服务端建立连接,只有客户端证书不为空,才会执行CA认证过滤器链逻辑。
注意 4:使用SSL/TLS单向认证方式或使用SSL/TLS双向认证方式与Kube-Apiserver服务端建立连接的话,执行Kube-Apiserver过滤器逻辑前已经建立好SSL/TLS连接。