k8s之user account
user account是在集群外部访问apiserver时使用的用户,比如kubectl命令就是作为kubernetes-admin用户来执行的,其中~/.kube/config指定了用户的证书,以便和apiserver互相认证。当然对于user account来说,是有多种认证方式的,参考官网,但是默认使能是x509客户端证书方式。
因为x509客户端证书认证采用双向认证,所以开始之前先通过此网址简单了解下https双向认证的原理和流程
一、Http
HyperText Transfer Protocol,超文本传输协议,是互联网上使用最广泛的一种协议,所有WWW文件必须遵循的标准。HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全。
使用TCP端口为:80
二、Https
Hyper Text Transfer Protocol over Secure Socket Layer,安全的超文本传输协议,网景公式设计了SSL(Secure Sockets Layer)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。
使用TCP端口默认为443
三、SSL协议加密方式
SSL协议即用到了对称加密也用到了非对称加密(公钥加密),在建立传输链路时,SSL首先对对称加密的密钥使用公钥进行非对称加密,链路建立好之后,SSL对传输内容使用对称加密。
对称加密
速度高,可加密内容较大,用来加密会话过程中的消息
公钥加密
加密速度较慢,但能提供更好的身份认证技术,用来加密对称加密的密钥
四、双向认证
双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证,具体过程如下:
image.png
1、客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
2、服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
3、客户端使用服务端返回的信息验证服务器的合法性,包括:
(1)证书是否过期。
(2)发型服务器证书的CA是否可靠。
(3)返回的公钥是否能正确解开返回证书中的数字签名。
(4)服务器证书上的域名是否和服务器的实际域名相匹配。
(5)验证通过后,将继续进行通信,否则,终止通信。
4、服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端。
5、验证客户端的证书,通过验证后,会获得客户端的公钥。
6、客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
7、服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
8、将加密方案通过使用之前获取到的公钥进行加密,返回给客户端。
9、客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端。
10、服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
下面我们要生成一个新的用户,并通过新用户并访问apiserver。
生成客户端证书
//生成客户端私钥
root@master:~/client# openssl genrsa -out client.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
................................................................................................................+++++
.................................+++++
e is 65537 (0x010001)
//根据私钥生成csr,-subj 中/CN指定了用户名tester
root@master:~/client# openssl req -new -key client.key -out client.csr -subj "/CN=tester"
//根据csr和根证书/etc/kubernetes/pki/ca.crt生成客户端证书
root@master:~/client# openssl x509 -req -in client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out client.crt -days 365
Signature ok
subject=CN = tester
Getting CA Private Key
//上面步骤生成了下面三个文件
root@master:~/client# ls
client.crt client.csr client.key
使用curl访问apiserver
这里验证使用curl命令携带客户端证书来访问apiserver,--insecure表示curl将跳过对server端证书的验证
root@master:~/client# curl --cert ./client.crt --key ./client.key --insecure -s $APISERVER/api
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "192.168.122.20:6443"
}
]
}
使用客户端证书访问apiserver,--cacert指定了server端证书,以便curl可以验证server
root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "192.168.122.20:6443"
}
]
}
上面使用client.crt证书访问apiserver时,首先经过了认证模块的认证,会被分配一个group system:authenticated,此group是系统自动创建的group,并且已经被默认关联到了下面的三个clusterrole,他们是有查看资源的权利,但是很受限,比如上面 访问/api是可以的
system:public-info-viewer
system:discovery
system:basic-user
下面尝试访问更多的资源,比如pod,就会报错,此请求被Forbidden,因为上面的三个clusterrole都没有访问pod的权利。
root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api/v1/namespaces/test/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"tester\" cannot list resource \"pods\" in API group \"\" in the namespace \"test\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
下面创建一个clusterrole,指定访问pod的权限后,将用户tester绑定到此clusterrole
//创建clusterrole,可以获取pod
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
namespace: test
name: test-pod
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
EOF
//查看刚创建的ClusterRole
root@master:~# kubectl describe ClusterRole test-pod
Name: test-pod
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list]
将用户tester绑定到刚创建的ClusterRole,再次尝试获取pod可以成功。
root@master:~# kubectl create rolebinding test -n test --clusterrole test-pod --user tester
rolebinding.rbac.authorization.k8s.io/test created
root@master:~/client# curl --cert ./client.crt --key ./client.key --cacert /etc/kubernetes/pki/ca.crt -s $APISERVER/api/v1/namespaces/test/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/test/pods",
"resourceVersion": "14001793"
},
"items": [
{
"metadata": {
"name": "test",
"namespace": "test",
"selfLink": "/api/v1/namespaces/test/pods/test",
"uid": "9c478764-ba05-4d64-817b-81ac3e67c06c",
"resourceVersion": "13943637",
"creationTimestamp": "2020-08-23T15:20:10Z",
"annotations": {
"cni.projectcalico.org/podIP": "10.24.166.148/32",
"cni.projectcalico.org/podIPs": "10.24.166.148/32",
"k8s.v1.cni.cncf.io/network-status": "[{\n \"name\": \"k8s-pod-network\",\n \"ips\": [\n \"10.24.166.148\"\n ],\n \"default\": true,\n \"dns\": {}\n}]",
"k8s.v1.cni.cncf.io/networks-status": "[{\n \"name\": \"k8s-pod-network\",\n \"ips\": [\n \"10.24.166.148\"\n ],\n \"default\": true,\n \"dns\": {}\n}]"
}
},
"spec": {
...
...
配置kubeconfig,使用kubectl访问apiserver
平时我们执行kubectl命令时,它会先读取配置文件~/.kube/config(在k8s种,这种文件被称为kubeconfig),获取客户端证书后,再访问apiserver。
现在我们要把上面生成的client.crt证书配置到~/.kube/config,让kubectl执行命令时,使用我们的客户端证书。
kubeconfig文件格式如下,其中clusters指定了要访问的k8s集群,可以配置多个,users指定了user account,contexts指定了使用哪个user,访问哪个集群,current-context 表示使用哪个context。
apiVersion: v1
kind: Config
clusters:
- cluster:
name: development
users:
- name: developer
contexts:
- context:
name: dev-frontend
user: test
current-context: ""
我们这里访问的是同一个集群,所以只需要修改user和context即可。使用下面三个命令进行设置,也可以直接修改配置文件。
//添加user tester,指定证书和key的位置
kubectl config --kubeconfig=/root/.kube/config set-credentials tester --client-certificate=/root/client/client.crt --client-key=/root/client/client.key
//创建一个context,指定访问的集群,用户和namespace。
//如果指定了namespace,则只能访问此namespace的资源
kubectl config --kubeconfig=/root/.kube/config set-context new_context --cluster=kubernetes --namespace=test --user=tester
//设置使用刚创建的context
kubectl config --kubeconfig=/root/.kube/config use-context new_context
在curl访问apiserver时已经将用户tester绑定到了ClusterRole test-pod,此ClusterRole只能访问test namespace下的pod,所以此时使用kubectl也只能访问test namespace下的pod。
root@master:~# kubectl describe rolebinding test -n test
Name: test
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: test-pod
Subjects:
Kind Name Namespace
---- ---- ---------
User tester
root@master:~#
root@master:~#
root@master:~# kubectl describe ClusterRole test-pod
Name: test-pod
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list]
kubectl可以获取 test namespace下的pod,并且不能获取kube-system下的pod
root@master:~/client# kubectl get pod -n test
NAME READY STATUS RESTARTS AGE
test 1/1 Running 0 7h31m
root@master:~/client# kubectl get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "tester" cannot list resource "pods" in API group "" in the namespace "kube-system"
验证完后,记得将context切换回默认的
kubectl config --kubeconfig=/root/.kube/config use-context kubernetes-admin@kubernetes
默认kubectl执行命令使用哪个用户呢?
在创建客户端证书时,需要在生成csr时会指定 -subj 的CN指定用户,说明证书中会保存用户的信息。在配置文件中~/.kube/config
client-certificate-data和client-key-data分别指定了客户端证书和私钥数据(经过base64加密),只要将client-certificate-data指向的数据base64解密后,就可以得知用户信息,操作如下:
//将client-certificate-data指向的数据复制到a.crt文件中
root@master:~/client# vim a.crt
//将a.crt中的数据解密
root@master:~/client# cat a.crt | base64 -d > b.crt
//通过openssl命令解析证书信息即可看到subject,O指定了用户组,CN指定了用户名
root@master:~/client# openssl x509 -in b.crt -text
Certificate:
Data:
...
Subject: O = system:masters, CN = kubernetes-admin
...
由上可知,该证书绑定的用户组是system:masters,用户名为kubernetes-admin。而集群中默认有个 ClusterRoleBinding 叫 cluster-admin,它将名为 cluster-admin 的 ClusterRole 和用户组 system:masters 进行了绑定,而名为 cluster-admin 的 ClusterRole 有集群范围的 Superadmin 权限,这也就理解了为什么默认的 Kubeconfig 能拥有极高的权限来操作 k8s 集群了。
root@master:~/client# kubectl describe ClusterRoleBinding cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
Role:
Kind: ClusterRole
Name: cluster-admin
Subjects:
Kind Name Namespace
---- ---- ---------
Group system:masters
root@master:~/client# kubectl describe ClusterRole cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
[*] [] [*]
参考
https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/
https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
https://blog.csdn.net/qianghaohao/article/details/100012855