Authentication(认证,确认双方是可信的):
1 ControllerManager、Scheduler于API Server部署在同一台机器,可以直接用API Server的非安全端口访问:--insecure-bind-address=127.0.0.1
2 kubectl、kube-proxy访问API Server时手动颁发证书进行HTTPS双向认证
3 kubelet
4 Pod通过ServiceAccount进行访问:service-account-token
Authorization(授权,是否可以执行某项操作):
授权策略(–authorization-mode):
Admission(准入控制,对资源的变更加上一些逻辑限制):
apiserver在将数据写入etcd前做一次拦截,对资源的操作进行一些逻辑控制。
引入了4个顶级资源:
Role是资源操作权限的集合,而RoleBinding则是将User、Group、ServiceAccount与Role绑定。
Role在创建时,需要与namespace绑定,如果需要创建跨namespace的角色,可以用ClusterRole。ClusterRole通常用于:
RoleBinding不一定只能使用Role绑定,而ClusterRoleBinding只能使用在ClusterRole。另外,由于Role在创建时必须指定namespace,实际使用时不太方便,因此,通常的使用方式是:创建ClusterRole,然后使用RoleBinding将ClusterRole与用户绑定。
k8s提供了4个顶级资源进行权限的授予,那么,在实际中该如何使用呢?
下面提供一种思路:
apiserver是K8S集群中所有组件协同工作的桥梁,因此,任何组件在实现时都需要访问apiserver。K8S将访问集群的用户分成两类:User和ServiceAccount。User是访问集群实际的用户,例如,使用kubectl访问集群的用户;而ServiceAccount则是访问集群的应用,也称为服务账号。
假设现在的场景是,我们需要创建一个用户,这个用户只能在develop这个命名空间中操作资源,SA虽然通常是Pod访问apiserver的方式,但是,也可以在外部通过SA访问集群。
// 创建命名空间
kubectl create namespace develop
// 创建SA(类似于创建用户),这个SA的名命名空间是develop
kubectl create sa my-sa -n develop
// 将admin集群角色绑定到develop命名空间的SA
kubectl create rolebinding my-rb --clusterrole=admin --serviceaccount=develop:my-sa -n develop
通过上面的方式,my-sa这个SA就只能访问develop这个命名空间中的所有资源,那么剩下的问题就是,如果客户端要用这个SA访问该怎么办呢?那就只有为用户生成kubeconfig文件。
如果是通过TOKEN的方式认证:
apiVersion: v1
clusters:
- name: $CLUSTER_NAME
cluster:
certificate-authority-data: $CA
server: $CLUSTER_URL
contexts:
- name: $USERNAME
context:
cluster: $CLUSTER_NAME
user: $USERNAME
namespace: $NAMESPACE
current-context: $USERNAME
kind: Config
preferences: {}
users:
- name: $USERNAME
user:
token: $TOKEN
从上面的文件结构来看,整个kubeconfig中有几个变量:
集群名称、集群域名、命名空间可以直接得到,剩下的用户名称、token和证书该如何得到呢?
SA包含三个部分:命名空间、token、证书。因此,可以直接用SA的名称、SA的token和SA的证书代替。有了上面的信息,就可以生成最终的kubeconfig文件。
同样的,如果使用User进行认证就需要使用证书,例如下面的kubeconfig文件:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: $CERTIFICATE_AUTHORITY_DATA
server: $CLUSTER_URL
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: $USERNAME
user:
client-certificate-data: $CLIENT_CERTIFICATE_DATA
client-key-data: $CLIENT_KEY_DATA
因此,要想让我们的客户端能够通过k8s的认证,就需要使用k8s的CA证书对私钥生成证书即可,然后就可以生成kubeconfig,那么k8s怎么知道当前用户是谁呢?因此,在生成证书时,提供的信息中就需要将CN(CommonName)设置为用户名,然后在k8s中再对用户进行授权,就可以进行访问了。
这种方式的认证流程就是:
因此,使用https相比于token的好处就是:token只验证了服务端,而https会对服务端和客户端都进行验证。
加密是为了保证数据的安全性
签名是为了保证数据的完整性
证书是为了保证公钥的完整性
加密一般分为对称加密和非对称加密:
相同的密钥
对数据进行加解密:明文+密钥->密文,密文+密钥->明文不同的密钥
对数据进行加解密:用公钥加密的密文只能用私钥解密,用私钥加密的密文只能用公钥解密对称加密的好处在于简单并且效率高,不好的当然就是密钥的分发问题。非对称加密的好处在于安全性高,不好的就是加解密效率比对称加密低。
签名就是对通信的数据打上标签,可以防止数据被篡改以及保证数据的真实性。
生成签名的过程:
验证签名的过程:
生成证书的过程:
通过上面生成证书的过程可以知道,证书主要包含两部分信息:自己的公钥和数字签名(只有用CA的公钥才能对数字签名进行验证)。
验证证书的过程:
根证书:
上面验证证书的过程中,有个问题没有解答:客户端如何得到签发证书的CA的公钥?
举个例子,当访问www.baidu.com
时,返回了百度的证书,为了得到并验证百度的公钥,又必须有签发给百度证书的GlobalSign Organization Validation CA机构的公钥,因此,客户端又必须有GlobalSign Organization Validation CA机构的证书,从而可以从中提取出百度的公钥。但是,怎么去验证GlobalSign Organization Validation CA的证书呢?又必须有签发给GlobalSign Organization Validation CA的证书公钥,即GlobalSign Root CA的公钥。这就构成了一个信任链,那么这个链在哪里结束呢?就是根证书,根证书是由权威机构给自己颁发的证书。
当前,权威的颁发根证书的机构并不多,可以认为,电脑中已经默认保存了大部分的权威机构的根证书,也就是这些证书是可以信任的。然后再用这些根证书去验证下面的机构或者网站的证书。
前面提到过对称加密和非对称加密的优缺点,而HTTPS就刚好结合了两者的优点:
单向认证就是我们通常访问网站的方式:只验证服务端是否是安全的。
认证流程:
上述过程只验证服务端是否安全,而没有验证客户端。
双向认证既需要验证服务端,又需要验证客户端。单向认证只为服务端生成了私钥和证书,而双向认证就需要为客户端和服务端分别生成私钥和证书。
认证流程:
kubernetes中的所有组件通信时都采用HTTPS双向认证,而部署时不可能为他们申请证书,因此,在部署kuberentes时通常都是先生成自签名证书,然后用该证书作为根证书,后续的证书都通过它签发。
mkdir -p /etc/crt
pushd /etc/crt
# 使用RSA算法生成私钥
openssl genrsa -out cakey.pem
# 根据私钥得到公钥,然后生成证书
# -new:生成新的证书请求文件
# -x509:结合-new表示生成证书文件
# -key:私钥
# -subj:机构信息(网站信息)
# -days:有效期
openssl req -new -x509 -key cakey.pem -out cacert.pem -subj '/CN=Mirror CA/O=UCloud/ST=GuangDong/L=Shenzhen/C=CN' -days 3650
cat cacert.pem >>/etc/pki/tls/certs/ca-bundle.crt
# 使用RSA算法生成私钥
openssl genrsa -out k8s.io.key 2048
# 生成证书请求文件
openssl req -new -key k8s.io.key -out k8s.io.csr -subj '/CN=*.k8s.io/O=UCloud/ST=GuangDong/L=Shenzhen/C=CN'
# 依据上面生成的CA证书和CA私钥,根据证书请求文件生成证书
# -in 证书请求文件
# -CA ca的证书
# -CAkey ca的私钥
# -CAcreateserial
# -extensions
openssl x509 -req -in k8s.io.csr -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out k8s.io.crt -days 3650 -config ./openssl.cfg -extensions k8s.io
popd