# 简介
K8S 中有两种用户 (User)—— 服务账号 (ServiceAccount) 和普通意义上的用户 (User)
ServiceAccount 是由 K8S 管理的,相当于系统账号。而 User 通常是在我们添加的,但 K8S 不存储用户列表 —— 也就是说,添加 / 编辑 / 删除用户都是在外部进行,无需与 K8S API 交互,虽然 K8S 并不管理用户,但是在 K8S 接收 API 请求时,是可以认知到发出请求的用户的。
而这里我主要介绍的是 User 普通用户。
通过以上介绍,我们知道了普通用户是不需要 api-server 存储的,那 api-server 是怎么判断用户是否为合法用户和它具有的权限的呢?我们带着这个问题往下看。
# api-service 用户验证(用户识别)
尽管 K8S 认知用户靠的只是用户的名字,但是只需要一个名字就能请求 K8S 的 API 显然是不合理的,所以依然需要验证此用户的身份
而 api-server 去验证用户主要通过以下几种情况:
这三种认证资料的生成都是和证书密不可分的。
・X509 客户端证书
客户端证书验证通过为 API Server 指定 --client-ca-file=xxx 选项启用,API Server 通过此 ca 文件来验证 API 请求携带的客户端证书的有效性,一旦验证成功,API Server 就会将客户端证书 Subject 里的 CN 属性作为此次请求的用户名
・静态 token 文件
通过指定 --token-auth-file=SOMEFILE 选项来启用 bearer token 验证方式,引用的文件是一个包含了 token, 用户名,用户 ID 的 csv 文件 请求时,带上 Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269 头信息即可通过 bearer token 验证
・静态密码文件
通过指定 --basic-auth-file=SOMEFILE 选项启用密码验证,类似的,引用的文件时一个包含 密码,用户名,用户 ID 的 csv 文件 请求时需要将 Authorization 头设置为 Basic BASE64ENCODED (USER:PASSWORD)
这里我们已经解答了前面的 api-server 是怎么识别用户的,但是这里又诞生了一个问题,api-server 怎么通过证书或者说 token、密钥文件来识别出用户是合法用户而不是假冒的用户?毕竟 api-server 理论上没保存用户的列表。
这里就涉及到用户的生成方式了。
# 用户的创建
为了让 api-server 能够准确的识别到用户为合法用户而不是假冒的,用户的证书在创建时需要经过 api-server 的 ca 进行签发。也就是说 api-server 签发过的证书就是合法用户。
其实就是 api-server 是第三方证书颁发机构的同时也是服务端。
# 生成一个私钥(RSA 算法私钥,我们访问 k8s 的凭证)
openssl genrsa -out test.key 2048 |
# 创建证书签名请求文件(预签发)
使用上述得到的私钥创建一个 csr (证书签名请求) 文件,其中我们需要在 subject 里带上用户信息 (CN 为用户名,O 为用户组)
这个用户名就是我们要创建的用户。用户组其实不重要,只是我们给这个证书分的组而已,在集群中没有任何意义。
openssl req -new -key test.key -out test.csr -subj "/CN=test/O=RUYUE" # 生成 crt,并使用我们的私钥进行签名 |
# 使用 ca 证书进行签发(给用户颁发证书)
这里主要就是使用 api-server 的 ca 证书去签发用户证书。
找到 api-server 的证书文件,在 api-server 的安装节点的 /etc/kubernetes/pki/ 路径下,会有两个文件,一个是 CA 证书 (ca.crt),一个是 CA 私钥 (ca.key)
openssl x509 -req -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out test.crt -days 365 #提取用户信息,并加上其他信息(比如颁发者等信息),用 CA 的私钥签发数字证书。 |
# k8s 用户的权限控制 (RBAC) 介绍
至此,我们已经解决了最初的两个问题之一(api-server 是怎么识别用户的),还剩下一个权限问题。
RBAC(Role-Based Access Control,基于角色的访问控制)在 Kubernetes 的 1.5 版本中引入,在 1.6 版本时升级为 Beta 版本,在 1.8 版本时升级为 GA。作为 kubeadm 安装方式的默认选项,足见其重要程度。
# RBAC 的概念
RBAC 引入了 4 个新的顶级资源对象: Role, ClusterRole,RoleBinding 和 ClusterRoleBinding. 同其他 API 资源对象一样,用户可以使用 kubectl 或者 API 调用等方式操作这些资源对象.
• Role: 角色,它定义了一组规则,定义了一组对Kubernetes API对象的操作权限
• Subject: 被作用者,既可以是”人”,也可以是机器,当然也可以是我们Kubernetes中定义的用户
• RoleBinding: 定义了”被作用者”和”角色”的绑定关系
# 角色(Role)
其实就相当于我给这个资源定义了一个组(角色),然后后续可以通过用户绑定实现这个组内的用户(subject)可以对这个资源做什么操作(还需要绑定)。
一个角色就是一组权限的集合,这里的权限都是许可形式的,不存在拒绝的规则,在一个命名空间中,可以用角色来定义一个角色,如果是集群级别的,就需要使用 ClusterRole 了.
角色只能对命名空间内的资源进行授权,在下面例子中定义的角色具备读取 Pod 的权限:
实际上,Role 本身就是一个 kubernetes 的 API 对象,定义文件如下:
kind: Role | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
namespace: test #这个Role作用的命名空间 | |
name: test-role | |
rules: | |
- apiGroups: [""] # ""空字符串,表示核心API群,支持的API组列表,例如"“apiVersion: batch/v1”“apiVersion: extensions:v1beta1”“apiVersion: apps/v1beta1”等” | |
resources: ["pods"] #支持的资源对象列表,例如Pods,deployments,jobs等 | |
verbs: ["get", "watch", "list"] #对资源对象的操作方法列表,例如get,watch,list,delete,replace,patch等 |
# 集群角色(ClusterRole)
本质上也是角色,只是它相当于更加广泛的角色,是集群级别的,不再是命名空间那么细了。
集群角色除了具有和角色一致的命名空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权.
主要用来绑定以下资源:
- 集群范围的资源,例如 Node.
- 非资源型的路径,例如 "/ealthz"
- 包含全部命名空间的资源,例如 Pods (用于 kubectl get pods --all-namespaces 这样的操作授权)
kind: ClusterRole | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
# ClusterRole 不受限于命名空间,所以无需设置namespace的名称 | |
rules: | |
- apiGroups: [""] | |
resources: ["pods"] | |
verbs: ["get", "watch", "list"] |
# 角色绑定(Rolebinding)和集群角色绑定(ClusterRolebinding)
其实就是将指定的角色给绑定到一个目标上,绑定目标可以是 User(用户)、Group(组)或者 Service Account,相当于给一个或一组对象进行赋予权限。
使用 RoleBinding 为某个命名空间授权,使用 ClusterRoleBinding 为集群范围内授权。
RoleBinding 可以引用 Role 进行授权。下面的例子中的 RoleBinding 将在 default 命名空间中把 pod-reader 角色授予用户 jane,这一操作可以让 jane 读取 default 命名空间中的 Pod:
kind: RoleBinding | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
name: example-rolebinding | |
namespace: default | |
subjects: | |
- kind: User | |
name: youmen | |
apiGroup: rbac.authorization.k8s.io | |
roleRef: | |
kind: Role | |
name: example-role | |
apiGroup: rbac.authorization.k8s.io |
在 Rolebinding 中定义了一个 subject 字段,即” 被作用者”。它的类型是 User,即 Kubernetes 里的用户,名称为 youmen
在 kubernetes 里的 User,也就是用户,只是一个授权系统里的逻辑概念。它需要通过外部认证服务,比如 Keystone,来提供。或者直接给 APIServer 指定一个用户名、密码文件。那么 kubernetes 的授权系统就能够从这个文件里找到对象的用户.
Rolebinding 对象通过 roleRef 字段可以直接通过名字,来引用前面定义的 Role 对象 (example-role),从而定义了” 被作用者 (Subject)” 和” 角色 (Role)” 之间的绑定关系
Role 和 RoleBinding 他们的权限限制规则仅仅在他们自己的 namespace 内有效,roleRef 也只能引用当前 namespace 里的 Role 对象
“RoleBinding 也可以引用 ClusterRole,对属于同一命名空间内 ClusterRole 定义的资源主体进行授权。一种常见的做法是集群管理员为集群范围预先定义好一组 ClusterRole,然后在多个命名空间中重复使用这些 ClusterRole。
kind: RoleBinding | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
name: read-secrets | |
namespace: development | |
# 集群角色中,只有development命名空间的权限才能赋予davesubjects | |
subjects: | |
- kind: User | |
name: dave | |
apiGroup: rbac.authorization.k8s.io | |
roleRef: | |
kind: ClusterRole | |
name: secret-reader | |
apiGroup: rbac.authorization.k8s.io |
# 给 test 用户授权(绑定资源组)
前面我们已经学习了 k8s 的权限控制,这里我们可以实践下,这里我们目标是让我们新建的 test 用户有 php 这个命名空间的所有权限。构造如下 role 和 rolebinding 即可。
# 赋予指定命名空间权限
创建如下 role 和 RoleBinding,则赋予了 test 这个账号对 php 这个命名空间的管理权限。
kind: Role | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
namespace: php | |
name: test_role | |
rules: | |
- apiGroups: [""] | |
resources: ["*"] | |
verbs: ["*"] |
kind: RoleBinding | |
apiVersion: rbac.authorization.k8s.io/v1 | |
metadata: | |
name: test_rolebinding | |
namespace: php | |
subjects: | |
- kind: User | |
name: test | |
roleRef: | |
kind: Role | |
name: test_role | |
apiGroup: rbac.authorization.k8s.io |
# 赋予所有命名空间权限(相当于让 test 变成超管)
k8s 中存在很多默认的 role,cluster-admin 就是其中一个。
apiVersion: rbac.authorization.k8s.io/v1 | |
kind: ClusterRoleBinding | |
metadata: | |
name: eviltest | |
subjects: | |
- apiGroup: rbac.authorization.k8s.io | |
kind: User | |
name: test | |
roleRef: | |
apiGroup: rbac.authorization.k8s.io | |
kind: ClusterRole | |
name: cluster-admin |
# 使用 test 用户访问指定资源
前面我们创建了一个用户,并为该用户分配了权限,接着我们就能使用这个用户去访问指定资源了。这里我们将这个用户绑定到 kubectl 配置文件中。
# 创建用户配置
告诉 kubectl test 用户的证书,此时。kube/config 文件内容如下
kubectl config set-credentials test --client-certificate=/home/momo/桌面/unhiden/test.crt --client-key=/home/momo/桌面/unhiden/test.key |
# 创建 api-server 配置
kubectl config set-cluster kubernetes --server=https://192.168.5.174:6443 --certificate-authority=/home/momo/桌面/unhiden/ca.crt |
此时,kube/config 文件内容如下
# 设置环境项中默认上下文
kubectl config set-context default --cluster=kubernetes --user=test |
设定使用 kubernetes 集群,使用用户 test 进行验证
# 设置默认环境项为 default
kubectl config use-context default |
# 访问指定资源
可以看到,由于我们前面设置的 rbac 规则,我们只能管控 php 的资源。