k8s集群权限管理

概述

任何请求访问k8s的kube-apiserver时都要依次经历这三个阶段:

  • 认证(Authentication,有时简写成AuthN):做身份校验,解决“你是谁?”
  • 授权(Authorization,有时简写AuthZ):做权限管控,解决“你能干什么?”,给予访问k8s集群中哪些资源以及做哪些操作的权利,比如你是否能创建一个pod是否能删除一个pod。
  • 准入控制(Admission Control):由一组控制逻辑级联而成,对对象进行拦截校验、更改等操作。比如在一个名为test的ns中创建一个pod,如果这个ns不存在那集群要不要自动创建出来?或者直接拒绝该请求?

mark

当然如果你的k8s集群开启了HTTP访问,就不再需要认证和授权流程了,显然这种配置风险太大。

认证

1
2
3
4
在认证阶段最重要的就是身份(Identity),我们需要从中获取到用户的相关信息。
Identity 信息可以通过 User 或者 Group 来定义,但是 Kubernetes 中其实并没有相关定义,所以你无法通过 Kubernetes API 接口进行创建、查询和管理。
Kubernetes 认为 User 这类信息由外部系统来管理,自己并不负责管理和设计,这样可以避免重复定义用户模型,方便第三方用户权限平台进行对接。
下面介绍几种常见的用户认证方式。
x509证书
1
2
3
4
5
6
7
8
k8s使用mTLS进行身份验证,通过解析请求使用的 客户端(client)证书,将其中的 subject 的通用名称(Common Name)字段(例如"/CN=bob")作为用户名。
Kubernetes 集群各个组件间相互通信,都是基于 x509 证书进行身份校验的。关于证书的创建、查看等。

比如使用openssl命令行工具生成一个证书签名请求(CSR):
openssl req -new -key zhangsan.pem -out zhangsan-csr.pem -subj "/CN=zhangsan/O=app1/O=app2"

这条命令会使用用户名zhangsan生成一个 CSR,且它属于 "app1" 和 "app2" 两个用户组,然后我们使用 CA 证书根据这个 CSR 就可以签发出一对证书。
当用这对证书去访问 APIServer 时,它拿到的用户就是zhangsan了。
Token
1
2
3
4
5
6
token又分为如下几种类型:
a、用户自己提供的静态Token,可以将这些 Token 写到一个 CSV 文件中,其中至少包含 3 列:分别为 Token、用户名和用户 ID。
你可以增加一个可选列包含 group 的信息,比如:
token1,user1,uid1,"group1,group2,group3"

APIServer 在启动时会通过参数--token-auth-file=xxxx来指定读取的 CSV 文件。不过这种方式,实际环境中基本上不会使用到。毕竟这种静态文件不方便修改,每次修改后还需要重新启动 APIServer。
ServiceAccount Token
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
这是 Kubernetes 中使用最为广泛的认证方式之一,主要用来给 Pod 提供访问 APIServer 的权限,通过使用 Volume 的方式挂载到 Pod 中。

当你创建一个 ServiceAccount 的时候,kube-controller-manager 会自动帮你创建出一个Secret来保存 Token,比如:
$ kubectl create sa demo
serviceaccount/demo created
➜ ~ kubectl get sa demo
NAME SECRETS AGE
demo 1 6s
➜ ~ kubectl describe sa demo
Name: demo
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: demo-token-fvsjg
Tokens: demo-token-fvsjg
Events: <none>

可以看到这里自动创建了一个名为demo-token-fvsjg的 Secret,我们来查看一下其中的内容:
$ kubectl get secret demo-token-fvsjg
NAME TYPE DATA AGE
demo-token-fvsjg kubernetes.io/service-account-token 3 27s
$ kubectl describe secret demo-token-fvsjg
Name: demo-token-fvsjg
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: demo
kubernetes.io/service-account.uid: f8fe4799-9add-4a36-8c29-a6b2744ba9a2
Type: kubernetes.io/service-account-token
Data
====
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Ildhc3plOFE0UXBlRE8xTFdsRThRVXktRF93T0otcW55VXI3R0RvV1IzVjgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlbW8tdG9rZW4tZnZzamciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY4ZmU0Nzk5LTlhZGQtNGEzNi04YzI5LWE2YjI3NDRiYTlhMiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlbW8ifQ.t0sNk8PiRIgMXaauzM8v8eW_AF7J5Su_TpyURaeBQX0BuFDpU-rrTC6h9sjetAQOLa6iLFsrG2tqH04pNo2N6TB73-K-M54veVpP6FGhceLO0Vsz_iTJuOsnkS_6agqfW0UrtaY8_oCk1OZipdbTJYZlmwlb6opcfP1j7bFHCdDbwfbWx8ilHqTaJ5_r7zrdhxsmC5ogtBRDaJfEYmsIBZSgnt_0qMHNj9L47n2mj_wo-aQQ25o0lbO_7RSeVA17kkgbAJ2wzwvv8-i3f7K23DSxab3k8trbuIRt1R3Gl33fv5WIwiz9okYIFfus4pe0MCtjBxxTMa526cdezKS4LQ
ca.crt: 1025 bytes
namespace: 7 bytes

Data里面的token我们可以到https://jwt.io/中 Decode 出来

Bootstrap Token 是 kubeadm 引入的方便创建新集群所使用的 Token 类型,通过如下类似的命令就可以将其加入新的节点中:
kubeadm join --discovery-token abcdef.1234567890abcdef

授权

1
2
3
4
k8s内部有多种授权模块,比如 Node、ABAC、RBAC、Webhook。
授权阶段会根据从AuthN拿到的用户信息,依次按配置的授权次序逐一进行权限验证。
任一授权模块验证通过,即允许该请求继续访问。
这里说下ABAC和RBAC。
ABAC
1
2
3
ABAC (Attribute Based Access Control) 是一种基于属性的访问控制,可以给 APIServer 指定一个 JSON 文件--authorization-policy-file=SOME_FILENAME,该文件描述了一组属性组合策略,比如:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "zhangsan", "namespace": "*", "resource": "pods", "readonly": true}}
这条策略表示,用户 zhangsan 可以以只读的方式读取任何 namespace 中的 Pod。
RBAC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
相对而言,RBAC使用起来就非常方便。
通过k8s对象就可以直接进行管理,也便于动态调整权限。
RBAC中引入角色,所有的权限都是围着这个角色进行展开的,每个角色里面定义了可以操作的资源以及操作方式。
在 Kubernetes 中有两种角色,一种是 namespace 级别的 Role ,一种是集群级别的 ClusterRole。

在 Kubernetes 中有些资源是 namespace 级别的,比如 Pod、Service 等,而有些则属于集群级别,比如 Node、PV 等。所以有了 Role 和 ClusterRole 两种角色。
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # 空字符串""表明使用core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]

这样一个角色表示可以访问 default 命名空间下面的 Pods,并可以对其进行 get、watch 以及 list 操作。
1
2
3
4
5
6
7
8
9
10
ClusterRole 除了可以定义集群方位的资源外,比如 Node,还可以定义跨 namespace 的资源访问,比如你想访问所有命名空间下面的 Pod,就可以这么定义:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# 鉴于ClusterRole是集群范围对象,所以这里不需要定义"namespace"字段
name: pods-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RBAC 中定义这些角色包含了一组权限规则,这些规则纯粹以累加形式组合,没有互斥的概念。
定义好角色,我们就可以做权限绑定了。这里分别有两个 API 对象,RoleBinding 和 ClusterRoleBinding。角色绑定就是把一个权限授予一个或者一组用户,例如:
apiVersion: rbac.authorization.k8s.io/v1

# 此角色绑定使得用户 "jane" 或者 "manager"组(Group)能够读取 "default" 命名空间中的 Pods
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane # 名称区分大小写
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: manager # 名称区分大小写
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # 这里可以是 Role,也可以是 ClusterRole
name: pods-reader # 这里的名称必须与你想要绑定的 Role 或 ClusterRole 名称一致
apiGroup: rbac.authorization.k8s.io

这里定义的 RoleBinding 对象在 default 命名空间中将 pods-reader 角色授予用户 jane和组 manager。
这一授权将允许用户 jane 和 manager 组中的各个用户从default 命名空间中读取到 Pod。

准入控制

1
2
准入控制可以帮助我们在 APIServer 真正处理对象前做一些校验以及修改的工作。
https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/#%E6%AF%8F%E4%B8%AA%E5%87%86%E5%85%A5%E6%8E%A7%E5%88%B6%E5%99%A8%E7%9A%84%E4%BD%9C%E7%94%A8%E6%98%AF%E4%BB%80%E4%B9%88

小结

1
2
3
作为一个企业级的容器管理调度平台,Kubernetes 在 Auth 方面设计得很完善,支持多种后端身份认证授权系统,比如 LDAP (Lightweight Directory Access Protocol)、Webhook 等。
AuthN 负责完成对用户的认证,并获取用户的相关信息(比如 Username、Groups 等)
而 AuthZ 则会根据 AuthN 返回的用户信息,根据配置的授权模式进行权限校验,来决定是否允许对某个 API 资源的操作请求。
-------------本文结束感谢您的阅读-------------
原创技术分享,感谢您的支持。