安全性是企业生产环境中的头等大事,对于访问同一集群的不同用户或者用户组来说,将权限分级是很有必要的。和很多云厂商一样,k8s也是采用按照角色和用户绑定的方式来分配权限的,这一节我们就来实际操作下,新建一个用户,并只让他在指定的namespace进行管理。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
RBAC,全称Role-based access control,会创建很多Role,每个Role对应着一系列的权限。通过将用户和Role进行绑定来给用户赋予不同类型的权限。
K8s中的资源要么是在某个namespace下,例如pod和service,要么是全局的,例如node。所有权限也就分为两种,Role下的权限是针对某个namespace的,在定义的时候必须要加上具体namespace;与之相对的ClusterRole下的权限是集群级别的,不用加namespace。
需要注意,所有的权限都是允许类型,而没有拒绝类型,所以赋予权限只能进行添加操作。一个用户绑定了某个Role,就只有Role下赋予的权限。
Role和ClusterRole都是集群中的单独资源,可以用yaml文件来创建。
例如下面是一个Role的声明
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
其中的apiGroups
和resources
是资源列表,可以参考官方API文档,而verbs
是允许对资源的操作动作,可以参考全部操作。
同样下面是一个ClusterRole的声明
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
name: secret-reader
rules:
- apiGroups: [""]
#
# at the HTTP level, the name of the resource for accessing Secret
# objects is "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
但是通常来说系统自带的Role和ClusterRole就基本够用了,如下
[root@k8s-master ~]# kubectl get role --all-namespaces
NAMESPACE NAME AGE
ingress-nginx ingress-nginx 6d19h
ingress-nginx ingress-nginx-admission 6d19h
kube-public kubeadm:bootstrap-signer-clusterinfo 16d
kube-public system:controller:bootstrap-signer 16d
kube-system extension-apiserver-authentication-reader 16d
kube-system kube-proxy 16d
kube-system kubeadm:kubelet-config-1.15 16d
kube-system kubeadm:nodes-kubeadm-config 16d
kube-system system::leader-locking-kube-controller-manager 16d
kube-system system::leader-locking-kube-scheduler 16d
kube-system system:controller:bootstrap-signer 16d
kube-system system:controller:cloud-provider 16d
kube-system system:controller:token-cleaner 16d
[root@k8s-master ~]# kubectl get clusterrole
NAME AGE
admin 16d
cluster-admin 16d
edit 16d
flannel 16d
ingress-nginx 6d19h
ingress-nginx-admission 6d19h
system:aggregate-to-admin 16d
system:aggregate-to-edit 16d
system:aggregate-to-view 16d
system:auth-delegator 16d
system:basic-user 16d
system:certificates.k8s.io:certificatesigningrequests:nodeclient 16d
system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 16d
system:controller:attachdetach-controller 16d
system:controller:certificate-controller 16d
system:controller:clusterrole-aggregation-controller 16d
system:controller:cronjob-controller 16d
system:controller:daemon-set-controller 16d
system:controller:deployment-controller 16d
system:controller:disruption-controller 16d
system:controller:endpoint-controller 16d
system:controller:expand-controller 16d
system:controller:generic-garbage-collector 16d
system:controller:horizontal-pod-autoscaler 16d
system:controller:job-controller 16d
system:controller:namespace-controller 16d
system:controller:node-controller 16d
system:controller:persistent-volume-binder 16d
system:controller:pod-garbage-collector 16d
system:controller:pv-protection-controller 16d
system:controller:pvc-protection-controller 16d
system:controller:replicaset-controller 16d
system:controller:replication-controller 16d
system:controller:resourcequota-controller 16d
system:controller:route-controller 16d
system:controller:service-account-controller 16d
system:controller:service-controller 16d
system:controller:statefulset-controller 16d
system:controller:ttl-controller 16d
system:coredns 16d
system:csi-external-attacher 16d
system:csi-external-provisioner 16d
system:discovery 16d
system:heapster 16d
system:kube-aggregator 16d
system:kube-controller-manager 16d
system:kube-dns 16d
system:kube-scheduler 16d
system:kubelet-api-admin 16d
system:node 16d
system:node-bootstrapper 16d
system:node-problem-detector 16d
system:node-proxier 16d
system:persistent-volume-provisioner 16d
system:public-info-viewer 16d
system:volume-scheduler 16d
view 16d
这里面带system:
前缀的是系统级别的,不建议修改和使用,而面向用户的,例如cluster-admin
,admin
,edit
,view
等则可以使用和修改,接下来的例子会看到。
将用户和Role进行绑定的操作就叫做RoleBinding,将用户和ClusterRole进行绑定的操作就叫做ClusterRoleBinding。
官方文档上也可以用yaml文件来进行这两种操作,但是通常直接用命令行即可,例如
kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
可以参考这里获得更多官方样例
既然提到了用户,不得不提一下k8s里面的用户以及认证。当然这是一个大的话题,这里先简单了解,后面再专门详细讲解。
k8s中的用户(user)分为两种,一种叫Service Account(SA),由k8s自己管理,一种是普通的user,由第三方来管理。我们这里要关心的就是第二种普通user。所有的API请求都必须跟一个user绑定,这也就意味着,任何API请求都必须先经过用户认证(Authentication)然后经过上面说的权限校验(Authorization)最后才到API。
不像Mysql这种集群,k8s自己内部是不保存用户信息的,都是由外部第三方来管理,那么如何进行用户认证呢?这就需要用到HTTPS中的一个概念,叫客户端证书(Client Certificate)。在k8s集群内部有一个权威机构(certificate Authority,CA)专门用来颁发证书,将用户信息提交到CA获得一个k8s认可的证书即可获得集群的信任。
下面的操作我们会详细看到这些步骤。
再次强调,用户认证和证书可以延伸很多,后面再写文章专门详细介绍
对HTTPS感兴趣的朋友,我后面会写一篇TLS1.3的wireshark抓包分析文章,欢迎大家关注我的csdn博客
在手动生成客户端证书的时候,官方向我们推荐了三款软件,分别是easyrsa,openssl和cfssl。可以在这里查看官方给出的一些简要介绍和脚本示例,下面的实际操作我们会选用CloudFlare家的cfssl来进行操作演示。
用户在访问k8s集群的时候需要携带自己的的认证信息,例如私钥和证书。于是kuberctl工具规定用户需要将这些信息连同API server的访问地址还有集群域名等等一起汇总填写到~/.kube/config
文件中,每次用户使用kubectl进行操作都会使用该文件进行认证。所以创建用户的根本目的就是创建该用户的config文件。
同时不管是集群内的还是集群外机器安装的kubectl,只要能读取到用户的config文件就可以正常访问到集群资源。可以参考我的另一篇博客《Kubernetes集群外Windows10机器的kubectl访问集群资源图文详解》。
下面以创建一个用户xiaofu,并只允许其到xiaofu-team这个namespace下进行管理为例进行实际操作。
前面说到需要得到集群内CA的认证才能获得证书,CA的信息都在master节点的/etc/kubernetes/pki
目录下
[root@k8s-master certs]# cd /etc/kubernetes/pki
[root@k8s-master pki]# ll
total 56
-rw-r--r--. 1 root root 1224 Apr 28 15:01 apiserver.crt
-rw-r--r--. 1 root root 1090 Apr 28 15:01 apiserver-etcd-client.crt
-rw-------. 1 root root 1671 Apr 28 15:01 apiserver-etcd-client.key
-rw-------. 1 root root 1675 Apr 28 15:01 apiserver.key
-rw-r--r--. 1 root root 1099 Apr 28 15:01 apiserver-kubelet-client.crt
-rw-------. 1 root root 1675 Apr 28 15:01 apiserver-kubelet-client.key
-rw-r--r--. 1 root root 1025 Apr 28 15:01 ca.crt
-rw-------. 1 root root 1675 Apr 28 15:01 ca.key
drwxr-xr-x. 2 root root 162 Apr 28 15:01 etcd
-rw-r--r--. 1 root root 1038 Apr 28 15:01 front-proxy-ca.crt
-rw-------. 1 root root 1675 Apr 28 15:01 front-proxy-ca.key
-rw-r--r--. 1 root root 1058 Apr 28 15:01 front-proxy-client.crt
-rw-------. 1 root root 1679 Apr 28 15:01 front-proxy-client.key
-rw-------. 1 root root 1675 Apr 28 15:01 sa.key
-rw-------. 1 root root 451 Apr 28 15:01 sa.pub
这里有CA以及各个核心组件的证书和私钥,我们创建的用户证书和私钥也可以放在这里。
首先下载cfssl工具,直接根据官方链接下载即可
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl_1.4.1_linux_amd64 -o cfssl
chmod +x cfssl
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssljson_1.4.1_linux_amd64 -o cfssljson
chmod +x cfssljson
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.4.1/cfssl-certinfo_1.4.1_linux_amd64 -o cfssl-certinfo
chmod +x cfssl-certinfo
下载后赋予可执行权限并添加到PATH
[root@k8s-master cfssl]# ll
total 35256
-rwxr-xr-x. 1 root root 14842064 May 15 12:43 cfssl
-rwxr-xr-x. 1 root root 11758832 May 15 12:46 cfssl-certinfo
-rwxr-xr-x. 1 root root 9495504 May 15 12:44 cfssljson
[root@k8s-master cfssl]# cp * /usr/local/bin
之后准备以下用户的个人信息,保存为如下json格式的证书请求文件
{
"CN": "",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "",
"L": "",
"O": "",
"OU": "",
"ST": ""
}
]
}
这里的CN
就会作为用户名,而O
就为作为用户组名,例如创建xiaofu-crs.json
文件如下
{
"CN": "xiaofu",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"O": "Beijing",
"OU": "k8s",
"ST": "System"
}
]
}
然后到/etc/kubernetes/pki
下根据上面的请求信息生成CA认证后的用户证书和私钥
[root@k8s-master pki]# cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /root/users/xiaofu/xiaofu-csr.json | cfssljson -bare xiaofu
2020/05/15 12:55:10 [INFO] generate received request
2020/05/15 12:55:10 [INFO] received CSR
2020/05/15 12:55:10 [INFO] generating key: rsa-2048
2020/05/15 12:55:10 [INFO] encoded CSR
2020/05/15 12:55:10 [INFO] signed certificate with serial number 696211841642757082046062313230328484866400029241
2020/05/15 12:55:10 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
[root@k8s-master pki]# ll xiaofu*
-rw-r--r--. 1 root root 997 May 15 12:55 xiaofu.csr
-rw-------. 1 root root 1679 May 15 12:55 xiaofu-key.pem
-rw-r--r--. 1 root root 1233 May 15 12:55 xiaofu.pem
成功以后会出现xiaofu-key.pem以及xiaofu.pem,分别是CA签名之后的私钥和证书
.pem/.key/.crt/.cer 这些格式都有可能表示证书和密钥,看不同工具的编码方式
之后就可以用这两个文件去生成用户专属的认证config文件了,
[root@k8s-master xiaofu]# pwd
/root/users/xiaofu
[root@k8s-master xiaofu]# kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://172.29.56.175:6443 --kubeconfig=xiaofu.config
Cluster "kubernetes" set.
kubectl config
命令专门用来创建和修改用户的config文件,这里创建了一个叫kubernetes
的cluster,并指明了该cluster的地址和CA证书,注意地址不能少了https://
会看到出现config文件,但是只包含集群的一些信息,没有用户的证书和私钥信息
[root@k8s-master xiaofu]# cat xiaofu.config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxxxx
server: https://172.29.56.175:6443
name: kubernetes
contexts: []
current-context: ""
kind: Config
preferences: {}
users: []
之后设置客户端认证证书
[root@k8s-master xiaofu]# kubectl config set-credentials xiaofu --client-certificate=/etc/kubernetes/pki/xiaofu.pem --client-key=/etc/kubernetes/pki/xiaofu-key.pem --embed-certs=true --kubeconfig=xiaofu.config
User "xiaofu" set.
[root@k8s-master xiaofu]# cat xiaofu.config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxxxx
server: https://172.29.56.175:6443
name: kubernetes
contexts: []
current-context: ""
kind: Config
preferences: {}
users:
- name: xiaofu
user:
client-certificate-data: xxxxx
client-key-data: xxxxx
可以看到config文件就多了用户的信息,因为太长我这里用xxxxx
代替了
Context是给一组访问参数起的一个名字,每个context由cluster,namespace,user组成,user和cluster是必须的,namespace可以不指定。同时config文件中还有一个current context
字段,kubectl用该字段来和集群进行沟通。如果config中配置了多个context的话,可以切换不同的context到current context。
首先创建一个新的namespace
kubectl create namespace xiaofu-team
然后给xiaofu用户设置context
[root@k8s-master xiaofu]# kubectl config set-context kubernetes --cluster=kubernetes --user=xiaofu --namespace=xiaofu-team --kubeconfig=xiaofu.config
Context "kubernetes" created.
[root@k8s-master xiaofu]# cat xiaofu.config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxxxx
server: https://172.29.56.175:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
namespace: xiaofu-team
user: xiaofu
name: kubernetes
current-context: ""
kind: Config
preferences: {}
users:
- name: xiaofu
user:
client-certificate-data: xxxxx
client-key-data: xxxxx
可以看到一个名叫kubernetes
的context被创建了,但是current-context
里面还没有使用
设置下current-context
[root@k8s-master xiaofu]# kubectl config use-context kubernetes --kubeconfig=xiaofu.config
Switched to context "kubernetes".
[root@k8s-master xiaofu]# cat xiaofu.config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxxxx
server: https://172.29.56.175:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
namespace: xiaofu-team
user: xiaofu
name: kubernetes
current-context: kubernetes
kind: Config
preferences: {}
users:
- name: xiaofu
user:
client-certificate-data: xxxxx
client-key-data: xxxxx
到这里用户的config文件就生成完毕
接着做一个rolebinding,对xiaofu用户赋予权限。
这里就不单独创造Role了,将k8s自带的admin角色绑定到xiaofu上,但是限制在xiaofu-team这个namespace里面,这样xiaofu就在xiaofu-team下拥有了管理员权限
[root@k8s-master xiaofu]# kubectl create rolebinding xiaofu-admin-binding --clusterrole=admin --user=xiaofu --namespace=xiaofu-team
rolebinding.rbac.authorization.k8s.io/xiaofu-admin-binding created
这样在任意能访问到API server的机器上,只要将刚才创建的config文件放到~/.kube/
目录下,该用户就可以以xiaofu的身份访问到集群了。
在k8s-master机器上创建xiaofu用户,并复制config文件到/home/xiaofu/.kube
下,改名为config
[root@k8s-master xiaofu]# useradd xiaofu
[root@k8s-master xiaofu]# mkdir /home/xiaofu/.kube
[root@k8s-master xiaofu]# cp xiaofu.config /home/xiaofu/.kube/config
[root@k8s-master xiaofu]# passwd xiaofu
Changing password for user xiaofu.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: all authentication tokens updated successfully.
因为是用root创建的文件,记得修改下config文件的权限
[root@k8s-master xiaofu]# chown xiaofu:xiaofu /home/xiaofu/.kube/config
之后切换到xiaofu用户登录k8s-master,会发现看不到别的namespace的信息
[xiaofu@k8s-master ~]$ kubectl get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "xiaofu" cannot list resource "pods" in API group "" in the namespace "kube-system"
创建的pod也是在xiaofu-team这个namespace下
[xiaofu@k8s-master ~]$ kubectl run xiaofu-nginx --image=mynginx:v2
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/xiaofu-nginx created
[xiaofu@k8s-master ~]$ kubectl get pod -o wide -n xiaofu-team
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xiaofu-nginx-6fdc85d5b7-tjd8c 1/1 Running 0 56s 10.244.1.177 k8s-node1
用root用户可以看到namespace
[root@k8s-master .kube]# kubectl get pod -o wide --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx ingress-nginx-controller-5575c6cd9d-mjncn 1/1 Running 0 47h 10.244.0.24 k8s-master
kube-system coredns-5d4dd4b4db-qcknv 1/1 Running 0 16d 10.244.0.3 k8s-master
kube-system coredns-5d4dd4b4db-wr4hh 1/1 Running 0 16d 10.244.0.2 k8s-master
kube-system etcd-k8s-master 1/1 Running 0 16d 172.29.56.175 k8s-master
kube-system kube-apiserver-k8s-master 1/1 Running 0 16d 172.29.56.175 k8s-master
kube-system kube-controller-manager-k8s-master 1/1 Running 0 16d 172.29.56.175 k8s-master
kube-system kube-flannel-ds-amd64-q6wf7 1/1 Running 0 16d 172.29.56.175 k8s-master
kube-system kube-flannel-ds-amd64-xdxbh 1/1 Running 0 45h 172.29.56.176 k8s-node1
kube-system kube-proxy-4fw7f 1/1 Running 0 8d 172.29.56.175 k8s-master
kube-system kube-proxy-brgtq 1/1 Running 0 8d 172.29.56.176 k8s-node1
kube-system kube-scheduler-k8s-master 1/1 Running 0 16d 172.29.56.175 k8s-master
xiaofu-team xiaofu-nginx-6fdc85d5b7-tjd8c 1/1 Running 0 2m35s 10.244.1.177 k8s-node1
总结下这一节的知识点
~/.kube/config
并设定好权限