九、集群认证授权与准入控制

API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其各种集群组件访问资源都需要经过网关才能进行正常访问和管理。每一次的访问请求都需要进行合法性的检验,其中包括身份验证、操作权限验证以及操作规范验证等,需要通过一系列验证通过之后才能访问或者存储数据到etcd当中。如下图:

9.1 Service Account

Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同

  • User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
  • User account是跨namespace的,而service account则是仅局限它所在的namespace;
  • 每个namespace都会自动创建一个default service account
  • Token controller检测service account的创建,并为它们创建secret
  • 开启ServiceAccount Admission Controller后
    • 每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccout)
    • 验证Pod引用的service account已经存在,否则拒绝创建
    • 如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中
    • 每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/

当创建 pod 的时候,如果没有指定一个 service account,系统会自动在与该pod 相同的 namespace 下为其指派一个default service account。而pod和apiserver之间进行通信的账号,称为serviceAccountName。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@k8s-master ~]$ kubectl  get pods
NAME READY STATUS RESTARTS AGE
busybox-6f99677459-qhjpd 1/1 Running 0 19h
statefulset-nginx-0 1/1 Running 0 18h
statefulset-nginx-1 1/1 Running 0 18h
statefulset-nginx-2 1/1 Running 0 18h
statefulset-nginx-3 1/1 Running 0 18h
statefulset-nginx-4 1/1 Running 0 18h
[root@k8s-master ~]$ kubectl get pods statefulset-nginx-0 -o yaml | grep -i serviceaccount
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
serviceAccount: default
serviceAccountName: default

[root@k8s-master ~]$ kubectl describe pod statefulset-nginx-1
Name: statefulset-nginx-1
Namespace: default
......
Volumes:
......
default-token-zl497:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-zl497
Optional: false

从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-*** token令牌,这就是pod和serviceaccount认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。每个 namespace 中都有一个默认的叫做 default 的 service account 资源。进行查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master ~]# kubectl  get sa 
NAME SECRETS AGE
default 1 8d
[root@k8s-master ~]# kubectl describe sa default
Name: default
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-zl497
Tokens: default-token-zl497
Events: <none>
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-zl497 kubernetes.io/service-account-token 3 8d

而默认的service account 仅仅只能获取当前Pod自身的相关属性,无法观察到其他名称空间Pod的相关属性信息。如果想要扩展Pod,假设有一个Pod需要用于管理其他Pod或者是其他资源对象,是无法通过自身的名称空间的serviceaccount进行获取其他Pod的相关属性信息的,此时就需要进行手动创建一个serviceaccount,并在创建Pod时进行定义。那么serviceaccount该如何进行定义呢???实际上,service accout也属于一个k8s资源,如下查看service account的定义方式

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
[root@k8s-master ~]# kubectl explain sa
KIND: ServiceAccount
VERSION: v1

DESCRIPTION:
ServiceAccount binds together: * a name, understood by users, and perhaps
by peripheral systems, for an identity * a principal that can be
authenticated and authorized * a set of secrets

FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources

automountServiceAccountToken <boolean>
AutomountServiceAccountToken indicates whether pods running as this service
account should have an API token automatically mounted. Can be overridden
at the pod level.

imagePullSecrets <[]Object>
ImagePullSecrets is a list of references to secrets in the same namespace
to use for pulling any images in pods that reference this ServiceAccount.
ImagePullSecrets are distinct from Secrets because Secrets can be mounted
in the pod, but ImagePullSecrets are only accessed by the kubelet. More
info:
https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod

kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds

metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata

secrets <[]Object>
Secrets is the list of secrets allowed to be used by pods running using
this ServiceAccount. More info:
https://kubernetes.io/docs/concepts/configuration/secret

9.1.1 ServiceAccount的创建

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
# --dry-run生成创建sa的yaml格式文件不运行命令,直接运行也可以创建mysa
[root@k8s-master ~]# kubectl create sa mysa -oyaml --dry-run
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: null
name: mysa
[root@k8s-master ~]# kubectl create sa mysa -oyaml --dry-run > mysa.yaml # 导出创建sa的yaml文件
[root@k8s-master ~]# kubectl apply -f mysa.yaml
serviceaccount/mysa created

[root@k8s-master ~]# kubectl get sa # 查看创建后的mysa
NAME SECRETS AGE
default 1 8d
mysa 1 4s

[root@k8s-master ~]# kubectl describe sa mysa # 查看mysa详细信息会发现挂载了一个secret
Name: mysa
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"creationTimestamp":null,"name":"mysa","namespace":"default"}}
Image pull secrets: <none>
Mountable secrets: mysa-token-7tf64
Tokens: mysa-token-7tf64
Events: <none>

[root@k8s-master ~]# kubectl get secrets # 查看自动生成的secret
NAME TYPE DATA AGE
default-token-zl497 kubernetes.io/service-account-token 3 8d
mysa-token-7tf64 kubernetes.io/service-account-token 3 24s

看到有一个 token 已经被自动创建,并被 service account 引用。设置非默认的 service account,只需要在 pod 的spec.serviceAccountName 字段中将name设置为您想要用的 service account 名字即可。在 pod 创建之初 service account 就必须已经存在,否则创建将被拒绝。需要注意的是不能更新已创建的 pod 的 service account

9.1.2 ServiceAccount的使用

创建一个pod使用上面的创建的mysa

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
[root@k8s-master sa]# vim nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
run: nginx
template:
metadata:
labels:
run: nginx
spec:
containers:
- image: hub.nnv5.cn/test/myapp:v2
name: nginx
serviceAccountName: mysa

[root@k8s-master sa]# kubectl apply -f nginx.yaml
deployment.apps/nginx created

[root@k8s-master sa]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-797f679bcf-jvjnp 1/1 Running 0 52s

[root@k8s-master sa]# kubectl describe pod nginx-797f679bcf-jvjnp | grep -i -A 6 'volumes'
Volumes:
mysa-token-7tf64:
Type: Secret (a volume populated by a Secret)
SecretName: mysa-token-7tf64 # 前面使用到的token
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>

在K8S集群当中,每一个用户对资源的访问都是需要通过apiserver进行通信认证才能进行访问的,那么在此机制当中,对资源的访问可以是token,也可以是通过配置文件的方式进行保存和使用认证信息,可以通过kubectl config进行查看配置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@k8s-master sa]# kubectl config view 
apiVersion: v1
clusters: # 集群列表(可以设置多个)
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.1.41:6443
name: kubernetes
contexts: # 上下文列表
- context: # 定义哪个集群可以被哪个用户访问(可以设置多个然后使用current-context设置切换不同集群)
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes # 当前使用上下文(切换到指定上下文使用上下文中配置的用户去访问配置的集群)
kind: Config
preferences: {}
users: # 定义用户列表
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED

在上面的配置文件当中,定义了集群、上下文以及用户。其中Config也是K8S的标准资源之一,在该配置文件当中定义了一个集群列表,指定的集群可以有多个;用户列表也可以有多个,指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。如图:定义了用户kubernetes-admin可以对kubernetes该集群的访问,用户kubernetes-user1对Clluster1集群的访问

9.1.3 自建证书账号访问apiserver演示

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 生成证书
[root@k8s-master pki]# openssl genrsa -out putianhui.key 2048
Generating RSA private key, 2048 bit long modulus
..............................................+++
.+++
e is 65537 (0x10001)

# 使用k8s集群原有的ca签署新证书
[root@k8s-master pki]# openssl req -new -key putianhui.key -out putianhui.csr -subj "/CN=putianhui"
[root@k8s-master pki]# openssl x509 -req -in putianhui.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out putianhui.crt -days 3650
Signature ok
subject=/CN=putianhui
Getting CA Private Key
[root@k8s-master pki]# openssl x509 -in putianhui.crt -text -noout


# 将putianhui用户添加到用户认证
[root@k8s-master pki]# kubectl config set-credentials putianhui --client-certificate=./putianhui.crt --client-key=./putianhui.key --embed-certs=true
User "putianhui" set.
[root@k8s-master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.1.41:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: putianhui # 这里为新添加的putianhui用户
user:
client-certificate-data: REDACTED
client-key-data: REDACTED


# 添加putianhui用户使用的集群上下文
[root@k8s-master pki]# kubectl config set-context putianhui@kubernetes --cluster=kubernetes --user=putianhui
Context "putianhui@kubernetes" created.
[root@k8s-master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.1.41:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context: # 这里为新添加的putianhui用户集群上下文
cluster: kubernetes
user: putianhui
name: putianhui@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: putianhui
user:
client-certificate-data: REDACTED
client-key-data: REDACTED

# 切换当前使用putianhui用户的集群上下文
[root@k8s-master pki]# kubectl config use-context putianhui@kubernetes
Switched to context "putianhui@kubernetes".

# 切换之后获取pod测试显示没有任何权限获取集群中的对象资源
[root@k8s-master pki]# kubectl get pods -o wide
Error from server (Forbidden): pods is forbidden: User "putianhui" cannot list resource "pods" in API group "" in the namespace "default"

9.2 RBAC基于角色的访问控制

Kubernetes的授权是基于插件形式的,其常用的授权插件有以下几种:

  • Node(节点认证)
  • ABAC(基于属性的访问控制)
  • RBAC(基于角色的访问控制)
  • Webhook(基于http回调机制的访问控制)

让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,随后在授权机制当中,只需要将权限授予某个角色,此时用户将获取对应角色的权限,从而实现角色的访问控制。如图:

基于角色的访问控制(Role-Based Access Control, 即”RBAC”)使用”rbac.authorization.k8s.io” API Group实现授权决策,允许管理员通过Kubernetes API动态配置策略

在k8s的授权机制当中,采用RBAC的方式进行授权,其工作逻辑是把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。此种方式仅作用于名称空间当中,这是什么意思呢?当User1绑定到Role角色当中,User1就获取了对该NamespaceA的操作权限,但是对NamespaceB是没有权限进行操作的,如get,list等操作。
另外,k8s为此还有一种集群级别的授权机制,就是定义一个集群角色(ClusterRole),对集群内的所有资源都有可操作的权限,从而将User2,User3通过ClusterRoleBinding到ClusterRole,从而使User2、User3拥有集群的操作权限。Role、RoleBinding、ClusterRole和ClusterRoleBinding的关系如下图:

但是这里有2种绑定ClusterRoleBinding、RoleBinding。也可以使用RoleBinding去绑定ClusterRole。
当使用这种方式进行绑定时,用户仅能获取当前名称空间的所有权限。为什么这么绕呢??举例有10个名称空间,每个名称空间都需要一个管理员,而该管理员的权限都是一致的。那么此时需要去定义这样的管理员,使用RoleBinding就需要创建10个Role,这样显得更加繁重。为此当使用RoleBinding去绑定一个ClusterRole时,该User仅仅拥有对当前名称空间的集群操作权限,换句话说,此时只需要创建一个ClusterRole就解决了以上的需求。

这里要注意的是:RoleBinding仅仅对当前名称空间有对应的权限。

在RBAC API中,一个角色包含了一套表示一组权限的规则。 权限以纯粹的累加形式累积(没有”否定”的规则)。 角色可以由命名空间(namespace)内的Role对象定义,而整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现。

9.3 Kubernetes Role演示

9.3.1 角色Role的创建和Rolebinding

User –> RoleBinding –> Role

Role的使用
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
# 语法:
kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]
# Name指定Role名称,--verb指定权限,--resource指定资源或者资源组,--dry-run单跑模式并不会创建


# 干跑创建一个名为pods-reader的role查看生成的yaml清单
[root@k8s-master /]$ kubectl create role pod-reader --verb=get,list,watch --resource=pods --dry-run -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role # 资源的类型
metadata:
name: pod-reader # Role的名称
namespace: default # 所属的名称空间(不指定为default默认的)
rules:
- apiGroups: # 对哪些api组内的资源进行操作
- ""
resources: # 对哪些资源定义
- pods
verbs: # 定义拥有什么权限
- get
- list
- watch

# 创建Role
[root@k8s-master /]$ kubectl create role pod-reader --verb=get,list,watch --resource=pods
role.rbac.authorization.k8s.io/pod-reader created
[root@k8s-master /]$ kubectl get role
NAME AGE
pod-reader 4s
[root@k8s-master /]# kubectl get role
NAME AGE
pod-reader 4s
[root@k8s-master /]# kubectl describe role pod-reader
Name: pod-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch] # 此处显示针对pods资源拥有哪些权限
Rolebinding的使用

RoleBinding可以引用在同一命名空间内定义的Role对象。

角色绑定也就是说将定义的对特定资源的特定权限赋予特定用户

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
# 语法:
kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run] [options]
# --role|--clusterrole指定绑定哪个角色,--user指定哪个用户
# --serviceaccount绑定到哪个名称空间的哪个serviceaccount

# 干跑查看创建rolebinding的资源清单
[root@k8s-master /]$ kubectl create rolebinding putianhui-rolebinding --role=pod-reader --user=putianhui -oyaml --dry-run
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: putianhui-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: putianhui

# 创建rolebinding
[root@k8s-master /]$ kubectl create rolebinding putianhui-rolebinding --role=pod-reader --user=putianhui
rolebinding.rbac.authorization.k8s.io/putianhui-rolebinding created

[root@k8s-master /]$ kubectl get rolebinding
NAME AGE
putianhui-rolebinding 6s

[root@k8s-master /]$ kubectl describe rolebinding putianhui-rolebinding #可以看到putianhui用户已经绑定到pod-reader这个role上面了
Name: putianhui-rolebinding
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: pod-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User putianhui

# 切换用户验证权限信息是否正确(切换集群用户到前面创建的putianhui用户上使用get pods查看信息)
[root@k8s-master /]$ kubectl config use-context putianhui@kubernetes
Switched to context "putianhui@kubernetes".

[root@k8s-master /]$ kubectl get pods # 使用get pods访问默认namespace没问题
NAME READY STATUS RESTARTS AGE
nginx-797f679bcf-jvjnp 1/1 Running 0 33h

[root@k8s-master /]# kubectl get pods -n ingress-nginx # 使用get pods访问ingress名称空间的pod报错。
Error from server (Forbidden): pods is forbidden: User "putianhui" cannot list resource "pods" in API group "" in the namespace "ingress-nginx"

[root@k8s-master /]$ kubectl get svc # 使用get svc提示没有权限(因为前面只授权了putianhui这个用户针对pods资源只有 get watch list这三个权限)
Error from server (Forbidden): services is forbidden: User "putianhui" cannot list resource "services" in API group "" in the namespace "default"

从上面的操作,可以总结出,role的定义和绑定,仅作用于当前名称空间,在获取ingress-nginx名称空间时,一样会出现Forbidden!!!

9.4 clusterRole与clusterRolebinding

User –> Clusterrolebinding –> Clusterrole

clusterRole的使用

ClusterRole对象可以授予与Role对象相同的权限,但由于它们属于集群范围对象, 也可以使用它们授予对以下几种资源的访问权限:

  • 集群范围资源(例如节点,即node)
  • 非资源类型endpoint(例如”/healthz”)
  • 跨所有命名空间的命名空间范围资源(例如pod,需要运行命令kubectl get pods --all-namespaces来查询集群中所有的pod)
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 切换到k8s集群管理员用户
[root@k8s-master /]$ kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".

# 删除前面创建的Role和Rolebinding
[root@k8s-master /]$ kubectl delete role pod-reader
role.rbac.authorization.k8s.io "pod-reader" deleted
[root@k8s-master /]$ kubectl delete rolebinding putianhui-rolebinding
rolebinding.rbac.authorization.k8s.io "putianhui-rolebinding" deleted

# 创建一个clusterRole和clusterRolebinding
[root@k8s-master /]$ kubectl create clusterrole read-all-pod-clusterole --verb=get,list,watch --resource=pods --dry-run -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: read-all-pod-clusterole
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch

[root@k8s-master /]$ kubectl get clusterrole
NAME AGE
read-all-pod-clusterole 6s

[root@k8s-master /]$ kubectl describe clusterrole read-all-pod-clusterole
Name: read-all-pod-clusterole
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]


## 创建clusterrolebinding
[root@k8s-master /]$ kubectl create clusterrolebinding cluster-rolebind --clusterrole=read-all-pod-clusterole --user=putianhui --dry-run -oyaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
name: cluster-rolebind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: read-all-pod-clusterole
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: putianhui

[root@k8s-master /]$ kubectl get clusterrolebinding
NAME AGE
cluster-admin 10d
cluster-rolebind 55s

[root@k8s-master /]$ kubectl describe clusterrolebinding cluster-rolebind
Name: cluster-rolebind
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: read-all-pod-clusterole
Subjects:
Kind Name Namespace
---- ---- ---------
User putianhui


## 切换到putianhui用户验证(因为clusterrole授予了pods的get wath list权限,因此可以使用get pod任何名称空间的内容,其他svc deploy这些是无法get到的,还有delete pod这些也是没有权限的)
[root@k8s-master secret]$ kubectl config use-context putianhui@kubernetes
Switched to context "putianhui@kubernetes".
[root@k8s-master secret]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox-6f99677459-qhjpd 1/1 Running 0 2d7h
nginx-797f679bcf-jvjnp 1/1 Running 0 35h
statefulset-nginx-0 1/1 Running 0 2d6h
statefulset-nginx-1 1/1 Running 0 2d6h
statefulset-nginx-2 1/1 Running 0 2d6h
statefulset-nginx-3 1/1 Running 0 2d6h
statefulset-nginx-4 1/1 Running 0 2d6h
[root@k8s-master secret]$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-58f68f5ccc-5v2qc 1/1 Running 0 9d

[root@k8s-master ~]$ kubectl get svc
Error from server (Forbidden): services is forbidden: User "putianhui" cannot list resource "services" in API group "" in the namespace "default"
[root@k8s-master ~]$ kubectl delete pod nginx-797f679bcf-jvjnp
Error from server (Forbidden): pods "nginx-797f679bcf-jvjnp" is forbidden: User "putianhui" cannot delete resource "pods" in API group "" in the namespace "default"

从上面的实验,我们可以知道对用户magedu进行集群角色绑定,用户putianhui将会获取对集群内所有资源的对应权限。

User –> Clusterrolebinding –> Clusterrole

将putianhui通过rolebinding到集群角色read-all-pod-clusterole当中,此时,putianhui仅作用于当前名称空间的所有pods资源的权限

clusterrole还可以通过rolebinding来进行绑定,一旦绑定成功之后用户拥有clusterrole的权限只能针对用户所在空间进行操作。

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
## rolebinding绑定clusterrole
# 删除前面创建的clusterrolebinding
[root@k8s-master ~]$ kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
[root@k8s-master ~]$ kubectl delete clusterrolebinding cluster-rolebind
clusterrolebinding.rbac.authorization.k8s.io "cluster-rolebind" deleted

# 查看前面创建的clusterrole权限(针对pod有get list watch权限,其他任何权限都没有)
[root@k8s-master ~]$ kubectl describe clusterrole read-all-pod-clusterole
Name: read-all-pod-clusterole
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]

# 创建rolebinding
[root@k8s-master ~]$ kubectl create rolebinding putianhui-rolebinding-clusterrole --clusterrole=read-all-pod-clusterole --user=putianhui
rolebinding.rbac.authorization.k8s.io/putianhui-rolebinding-clusterrole created
[root@k8s-master ~]$ kubectl describe rolebinding putianhui-rolebinding-clusterrole
Name: putianhui-rolebinding-clusterrole
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: read-all-pod-clusterole
Subjects:
Kind Name Namespace
---- ---- ---------
User putianhui

# 切换到putianhui用户查看用户权限
[root@k8s-master ~]$ kubectl config use-context putianhui@kubernetes
Switched to context "putianhui@kubernetes".
[root@k8s-master ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-797f679bcf-jvjnp 1/1 Running 0 47h
[root@k8s-master ~]$ kubectl get pods -n kube-system
Error from server (Forbidden): pods is forbidden: User "putianhui" cannot list resource "pods" in API group "" in the namespace "kube-system"
[root@k8s-master ~]$ kubectl get pods -n ingress-nginx
Error from server (Forbidden): pods is forbidden: User "putianhui" cannot list resource "pods" in API group "" in the namespace "ingress-nginx"

9.5 RBAC的三种授权访问

RBAC不仅仅可以对user进行访问权限的控制,还可以通过group和serviceaccount进行访问权限控制。当我们想对一组用户进行权限分配时,即可将这一组用户归并到一个组内,从而通过对group进行访问权限的分配,达到访问权限控制的效果。

从前面serviceaccount我们可以了解到,Pod可以通过 spec.serviceAccountName来定义其是以某个serviceaccount的身份进行运行,当我们通过RBAC对serviceaccount进行访问授权时,即可以实现Pod对其他资源的访问权限进行控制。也就是说,当我们对serviceaccount进行rolebinding或clusterrolebinding,会使创建Pod拥有对应角色的权限和apiserver进行通信。如图:

9.6 小节总结

1
2
3
4
5
6
7
API Server:
subject --> action --> object
认证方式:token/tls/用户密码
账号:UserAccont/ServiceAccount
授权方式: role/rolebinding/clusterrole/clusterrolebinding
subject:user/group/servieaccount
object:resouce group/resource/non-resource url