k8s角色权限RBAC&ClusterRole
k8s角色权限RBAC&ClusterRole
三个最基本的概念
Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
Subject:被作用者,既可以是“人”,也可以是“机器”,也可以是你在 Kubernetes 里定义的“用户”。
RoleBinding:定义了“被作用者”和“角色”的绑定关系。
而这三个概念,其实就是整个 RBAC 体系的核心所在
Role 本身就是一个 Kubernetes 的 API 对象,定义如下
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: mynamespace
name: example-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
然后,这个 Role 对象的 rules 字段,就是它所定义的权限规则。在上面的例子里,这条规则的含义就是:允许“被作用者”,对 mynamespace 下面的 Pod 对象,进行 GET、WATCH 和 LIST 操作。
这个具体的“被作用者”又是如何指定的呢?这就需要通过 RoleBinding 来实现了。
当然,RoleBinding 本身也是一个 Kubernetes 的 API 对象。它的定义如下
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-rolebinding
namespace: mynamespace
subjects:
- kind: User
name: example-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: example-role
apiGroup: rbac.authorization.k8s.io
这个 RoleBinding 对象里定义了一个 subjects 字段,即“被作用者”。它的类型是 User,即 Kubernetes 里的用户。这个用户的名字是 example-user。
问题:在 Kubernetes 中,其实并没有一个叫作“User”的 API 对象。而且,我们在前面和部署使用 Kubernetes 的流程里,既不需要 User,也没有创建过 User。这个 User 到底是从哪里来的呢?
实际上,Kubernetes 里的“User”,也就是“用户”,只是一个授权系统里的逻辑概念。它需要通过外部认证服务,比如 Keystone,来提供。或者,你也可以直接给 APIServer 指定一个用户名、密码文件。那么 Kubernetes 的授权系统,就能够从这个文件里找到对应的“用户”了。当然,在大多数私有的使用环境中,我们只要使用 Kubernetes 提供的内置“用户”,就足够了
roleRef 字段:正是通过这个字段,RoleBinding 对象就可以直接通过名字,来引用我们前面定义的 Role 对象(example-role),从而定义了“被作用者(Subject)”和“角色(Role)”之间的绑定关系。需要再次提醒的是,Role 和 RoleBinding 对象都是 Namespaced 对象(Namespaced Object),它们对权限的限制规则仅在它们自己的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。
扩展提问:对于非 Namespaced(Non-namespaced)对象(比如:Node),或者,某一个 Role 想要作用于所有的 Namespace 的时候,我们又该如何去做授权呢?
要使用 ClusterRole 和 ClusterRoleBinding 这两个组合了。这两个 API 对象的用法跟 Role 和 RoleBinding 完全一样。只不过,它们的定义里,没有了 Namespace 字段
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-clusterrole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-clusterrolebinding
subjects:
- kind: User
name: example-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: example-clusterrole
apiGroup: rbac.authorization.k8s.io
名叫 example-user 的用户,拥有对所有 Namespace 里的 Pod 进行 GET、WATCH 和 LIST 操作的权限
在 Role 或者 ClusterRole 里面,如果要赋予用户 example-user 所有权限,那你就可以给它指定一个 verbs 字段的全集
ClusterRoleBinding
部分:- 不需要修改,因为它只是将
ClusterRole
绑定到用户example-user
。
- 不需要修改,因为它只是将
ClusterRole
的rules
部分:apiGroups: ["*"]
:表示对所有 API 组生效(包括核心 API 组和其他自定义 API 组)。resources: ["*"]
:表示对所有资源生效(如 Pods、Deployments、Services 等)。verbs: ["*"]
:表示赋予所有操作权限(包括get
、list
、watch
、create
、update
、patch
、delete
等)
ClusterRole
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-clusterrole
rules:
- apiGroups: ["*"] # 表示所有 API 组
resources: ["*"] # 表示所有资源
verbs: ["*"] # 表示所有操作权限
# verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
#这样写也行
Role 或者 ClusterRole同理
记得加上namespace
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: mynamespace # 指定命名空间
name: example-role
rules:
- apiGroups: ["*"] # 所有 API 组
resources: ["*"] # 所有资源
verbs: ["*"] # 所有操作权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-rolebinding
namespace: mynamespace # 指定命名空间
subjects:
- kind: User
name: example-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: example-role
apiGroup: rbac.authorization.k8s.io
示例
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["my-config"]
verbs: ["get"]
这条规则的“被作用者”,只对名叫“my-config”的 ConfigMap 对象,有进行 GET 操作的权限。
Kubernetes 负责管理的“内置用户”:ServiceAccount。
学会ServiceAccount 分配权限
定义一个 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: mynamespace
name: example-sa
只需要 Name 和 Namespace 这两个最基本的字段。
编写 RoleBinding 的 YAML 文件,来为这个 ServiceAccount 分配权限:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-rolebinding
namespace: mynamespace
subjects:
- kind: ServiceAccount
name: example-sa
namespace: mynamespace
roleRef:
kind: Role
name: example-role
apiGroup: rbac.authorization.k8s.io
RoleBinding 对象里,subjects 字段的类型(kind),不再是一个 User,而是一个名叫 example-sa 的 ServiceAccount。而 roleRef 引用的 Role 对象,依然名叫 example-role,也就是我在这篇文章一开始定义的 Role 对象。
用 kubectl 命令创建这三个对象:
$ kubectl create -f svc-account.yaml
$ kubectl create -f role-binding.yaml
$ kubectl create -f role.yaml
查看一下这个 ServiceAccount 的详细信息
$ kubectl get sa -n mynamespace -o yaml
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2018-09-08T12:59:17Z
name: example-sa
namespace: mynamespace
resourceVersion: "409327"
...
secrets:
- name: example-sa-token-vmfg6
Kubernetes 会为一个 ServiceAccount 自动创建并分配一个 Secret 对象,就是这个 ServiceAccount 对应的、用来跟 APIServer 进行交互的授权文件,我们一般称它为:Token。
这时候,用户的 Pod,就可以声明使用这个 ServiceAccount 了
apiVersion: v1
kind: Pod
metadata:
namespace: mynamespace
name: sa-token-test
spec:
containers:
- name: nginx
image: nginx:1.7.9
serviceAccountName: example-sa
我定义了 Pod 要使用的要使用的 ServiceAccount 的名字是:example-sa。
等这个 Pod 运行起来之后,我们就可以看到,该 ServiceAccount 的 token,也就是一个 Secret 对象,被 Kubernetes 自动挂载到了容器的 /var/run/secrets/kubernetes.io/serviceaccount 目录下,如下所示:
$ kubectl describe pod sa-token-test -n mynamespace
Name: sa-token-test
Namespace: mynamespace
...
Containers:
nginx:
...
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from example-sa-token-vmfg6 (ro)
通过 kubectl exec 查看到这个目录里的文件:
$ kubectl exec -it sa-token-test -n mynamespace -- /bin/bash
root@sa-token-test:/# ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
容器里的应用,就可以使用这个 ca.crt 来访问 APIServer 了。更重要的是,此时它只能够做 GET、WATCH 和 LIST 操作。因为 example-sa 这个 ServiceAccount 的权限,已经被我们绑定了 Role 做了限制。
一个 Pod 没有声明 serviceAccountName会怎样
如果一个 Pod 没有声明 serviceAccountName,Kubernetes 会自动在它的 Namespace 下创建一个名叫 default 的默认 ServiceAccount,然后分配给这个 Pod。
默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。当然,这个访问所需要的 Token,还是默认 ServiceAccount 对应的 Secret 对象为它提供的
sa
:sa
是serviceaccount
的缩写,表示服务账户
$kubectl describe sa default
Name: default
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-s8rbq
Tokens: default-token-s8rbq
Events: <none>
$ kubectl get secret
NAME TYPE DATA AGE
kubernetes.io/service-account-token 3 82d
$ kubectl describe secret default-token-s8rbq
Name: default-token-s8rbq
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name=default
kubernetes.io/service-account.uid=ffcb12b2-917f-11e8-abde-42010aa80002
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 7 bytes
token: <TOKEN数据>
Kubernetes 会自动为默认 ServiceAccount 创建并绑定一个特殊的 Secret:它的类型是kubernetes.io/service-account-token;它的 Annotation 字段,声明了kubernetes.io/service-account.name=default,即这个 Secret 会跟同一 Namespace 下名叫 default 的 ServiceAccount 进行绑定。
生产环境中,我强烈建议你为所有 Namespace 下的默认 ServiceAccount,绑定一个只读权限的 Role。
Kubernetes 还拥有“用户组”(Group)的概念
一个 ServiceAccount,在 Kubernetes 里对应的“用户”的名字
system:serviceaccount:<Namespace名字>:<ServiceAccount名字>
它对应的内置“用户组”的名字,就是
system:serviceaccounts:<Namespace名字>
这两个对应关系,请你一定要牢记。
现在我们可以在 RoleBinding 里定义如下的 subjects
subjects:
- kind: Group
name: system:serviceaccounts:mynamespace
apiGroup: rbac.authorization.k8s.io
这就意味着这个 Role 的权限规则,作用于 mynamespace 里的所有 ServiceAccount。这就用到了“用户组”的概念。
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
就意味着这个 Role 的权限规则,作用于整个系统里的所有 ServiceAccount。
在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。你可以通过 kubectl get clusterroles 查看到它们。
Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:
cluster-admin;admin;edit;view。
上面这个 cluster-admin 角色,对应的是整个 Kubernetes 项目中的最高权限(verbs=*)
请你务必要谨慎而小心地使用 cluster-admin。