RBAC
在互联网级别的大规模集群中,Kubernetes内置的编排对象,很难做到满足所有需求。所以,很多实际的容器化工作,都会要求你设计一个自己的编排对象,事先自己的控制器模式。在Kubernetes中,我们可以通过CRD机制来完成这种工作,但是,在Kubernetes里新增和操作API对象,就必须了解RBAC。Kubernetes中所有的API对象都是保存在etcd中,对这些API对象的操作都是通过访问api-server实现的。你需要API Server来帮助你做授权操作。
在Kubernetes中,负责完成授权工作的机制,就是RBAC:基于角色的访问控制。
RBAC中的三个基本概念:
- Role:角色,就是一组规则,定义了一组对Kubernetes API对象的操作权限
- Subject:被作用者,既可以是人,也可以是机器,也可以是你在Kubernetes中定义的用户
- RoleBinding:定义了“被作用者”和“角色”的绑定关系
Role
Role本身就是一个Kubernetes的API对象,定义如下:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: mynamespace
name: example-role
rules:
- apiGroups: [""]
resources: ["pod"]
verbs: ["get","watch","list"]
这个Role对象指定了它能产生作用的Namespace是mynamespace
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对象可以直接通过名字,来引用前面定义的Role对象,从而定义了被作用者和角色之间的关系
RoleBinding和Role对象都是Namespaced对象,它们对权限的限制规则仅在它们自己的Namespace内有效,roleRef也只能引用当前Namespace里的Role对象
ClusterRole和ClusterRoleBinding
对于非Namespaced对象(比如Node)或者一个Role想作用于所有的Namespace的时候,我们可以使用ClusterRole和ClusterRoleBinding做授权。这两个API对象的用法跟Role和RoleBinding完全相同,只不过没有了namespace字段
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-cluster
rule:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-rolebinding
subjects:
- kind: User
name: example-user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: example-clusterrole
apiGroup: rbac.authorization.k8s.io
上面的例子中ClusterRole和ClusterRoleBinding的组合,意味着名叫example-role的用户,拥有对所有Namespace的Pod进行get、watch、list操作的权限。
如果在Role或者ClusterRole中,如果要赋予用户example-user所有权限,那可以给它指定一个verbs字段的全集
verbs: ["get","watch","list","update","create","patch","delete"]
ServiceAccount
在大多数时候,我们都不太使用“用户”这个功能,而是使用Kubernetes里的“内置用户”
首先,我们定义一个ServiceAccount。
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: mynamespace
name: example-sa
然后我们通过Role和RoleBinding的YAML文件,为这个ServiceAccount分配权限:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-role
namespace: mynamespace
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
---
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
操作演示
我们先创建上面三个对象
[root@host1 rbac]# kubectl create namespace mynamespace
namespace/mynamespace created
[root@host1 rbac]# kubectl get namespace
NAME STATUS AGE
default Active 2d19h
kube-public Active 2d19h
kube-system Active 2d19h
mynamespace Active 5s
rook-ceph Active 42h
[root@host1 rbac]# kubectl create -f svc-account.yaml
serviceaccount/example-sa created
[root@host1 rbac]# kubectl create -f role-binding.yaml
role.rbac.authorization.k8s.io/example-role created
rolebinding.rbac.authorization.k8s.io/example-rolebinding created
然后,我们查看一下这个ServiceAccount的详细信息
[root@host1 rbac]# kubectl get sa -n mynamespace -o yaml
apiVersion: v1
items:
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2019-10-25T02:15:24Z"
name: default
namespace: mynamespace
resourceVersion: "474819"
selfLink: /api/v1/namespaces/mynamespace/serviceaccounts/default
uid: 4da5a943-f6cd-11e9-928f-000c296c79f3
secrets:
- name: default-token-ncwxl
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2019-10-25T02:15:46Z"
name: example-sa
namespace: mynamespace
resourceVersion: "474876"
selfLink: /api/v1/namespaces/mynamespace/serviceaccounts/example-sa
uid: 5aeef1d2-f6cd-11e9-928f-000c296c79f3
secrets:
- name: example-sa-token-vg2sk
kind: List
metadata:
resourceVersion: ""
selfLink: ""
Kubernetes会为每一个ServiceAccount自动创建并分配一个Secret对象,即Secrets字段
这个Secret,就是这个ServiceAccount用来和API Server进行交互的授权文件,我们称它为:ServiceAccount Token.
这时候,用户的Pod,就可以声明使用这个ServiceAccount了,比如下面这个例子:
apiVersion: v1
kind: Pod
metadata:
namespace: mynamespace
name: sa-token-test
spec:
containers:
- name: nginx
image: nginx:1.7.9
serviceAcccountName: example-sa
在Pod中,我们指定了ServiceAccountName为example-sa
这个Pod运行起来之后,该ServiceAccount的token就会被自动挂载到容器的/var/run/secrets/kubernetes.io/serviceaccount目录下。
如果一个Pod没有声明ServiceAccountName,Kubernetes会自动在它的Namespace下创建一个名叫default的默认ServiceAccount,然后分配给这个Pod。这个默认的ServiceAccount没有关联任何Role。也就是说,此时它有访问API Server的绝大多数权限。
Kubernetes中的用户组
除了前面使用的“用户”,Kubernetes还有用户组的概念,也就是一组用户的意思。如果你为Kubernetes配置了外部认证服务的话,这个用户组的概念由外部认证服务提供。
但是对于Kubernetes内置用户ServiceAccount来说,上述用户组也同样使用。
实际上,一个ServiceAccount,在Kubernetes里对应的“用户”名字是:
system:serviceaccount:
而它对应的内置“用户组”的名字就是:
system:serviceaccounts:
比如,我们可以在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来供用户直接使用:
- cluster-admin(Kubernetes中的最高权限)
- admin
- edit
- view