API服务的安全防护(二)
通过基于角色的权限控制加强集群安全
在Kubernetes1.8.0版本中,RBAC 授权插件升级为GA(通用可用性),并且在很多集群上默认开启。 RBAC 会阻止未授权的用户查看和修改集群状态。除非你授予默认的 ServiceAccount 额外的特权,否则默认的 ServiceAccount 不允许查看集群状态,更不用说以任何方式去修改集群状态。
注意 除了 RBAC 插件,Kubernetes 也包含其他的授权插件,比如基于属性的访问控制插件 (ABAC)、WebHook 插件和自定义插件实现。但是,RBAC 插件是标准的。
介绍RBAC授权插件
Kubernetes API 服务器可以配置使用一个授权插件来检查是否允许用户请求的动作执行。 因为 API 服务器对外暴露了 REST 接口, 用户可以通过向服务器发送 HTTP 请求来执行动作, 通过在请求中包含认证凭证来进行认证(认证 token、用户名和密码或者客户端证书)。
了解动作
但是有什么动作? REST 客户端发送 GET、 POST、 PUT、DELETE 和其他类型的 HTTP 请求到特定的 URL 路径上, 这些路径表示特定的 REST 资源。 在 Kubernetes 中, 这些资源是 Pod、 Service、 Secret, 等等。 以下是 Kubernetes 请求动作的一些例子:
- 获取 pod
- 创建服务
- 更新密钥
RBAC 这样的授权插件运行在 API 服务器中,它会决定一个客户端是否允许在请求的资源上执行请求的动词。
了解 RBAC 插件
顾名思义, RBAC 授权插件将用户角色作为决定用户能否执行操作的关键因素。主体(可以是一个人、一个 ServiceAccount, 或者一组用户或 ServiceAccount)和 一个或多个角色相关联, 每个角色被允许在特定的资源上执行特定的动词。
如果一个用户有多个角色, 他们可以做任何他们的角色允许他们做的事情。 如果用户的角色都没有包含对应的权限, 例如, 更新密钥, API 服务器会阻止用户 3 个 “他的” 对密钥执行 PUT 或 PATCH 请求。
通过 RBAC 插件管理授权是简单的, 这一切都是通过创建四种 RBAC 特定的Kubernetes 资源来完成的。
介绍RBAC资源
RBAC 授权规则是通过四种资源来进行配置的, 它们可以分为两个组
- Role( 角色)和 ClusterRole (集群角色), 它们指定了在资源上可以执行哪些动词。
- RoleBinding (角色绑定) 和 ClusterRoleBinding (集群角色绑定), 它们将上述角色绑定到特定的用户、 组或 ServiceAccounts 上。
角色定义了可以做什么操作,而绑定定义了谁可以做这些操作
角色和集群角色, 或者角色绑定和集群角色绑定之间的区别在于角色和角色绑定是命名空间的资源, 而集群角色和集群角色绑定是集群级别的资源(不是命名空间的)。同样地, 可以创建多个集群绑定和集群角色。 图中显示的另外一件事情是,尽管角色绑定是在命名空间下的, 但它们也可以引用不在命名空间下的集群角色。
创建命名空间和运行pod
[root@master ~]# kubectl create ns foo
[root@master ~]# kubectl run test --image=luksa/kubectl-proxy -n foo
[root@master ~]# kubectl create ns bar
[root@master ~]# kubectl run test --image=luksa/kubectl-proxy -n bar
[root@master ~]# kubectl exec -it test -n foo sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "services is forbidden: User \"system:serviceaccount:bar:default\" cannot list resource \"services\" in API group \"\" in the namespace \"foo\"",
"reason": "Forbidden",
"details": {
"kind": "services"
},
"code": 403
}/ #
localhost:8001,这是 kubectlproxy 进程监听的地址。这个进程接收到请求并将其发送到API 服务器,同时以 foo 命名空间中默认的 ServiceAccount 进行身份认证。
API服务器响应表明 ServiceAccount 不允许列出 foo 命名空间中的服务,即使 pod 就运行在同一个命名空间中。可以看到 RBAC 插件已经起作用了。ServiceAccount 的默认权限不允许它列出或修改任何资源。
使用Role和RoleBinding
Role资源定义了哪些操作可以在哪些资源上执行(哪种类型的 HTTP 请求可以在哪些 RESTful 资源上执行)。下面的代码清单定义了一个Role,它允许用户获取并列出 foo 命名空间中的服务。
vim service-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: foo # Role所在的命名空间(如果没有填写命名空间则使用当前的命名空间)
name: service-reader
rules:
- apiGroups: [""] # Service是核心 apiGroup 的资源,所以没有apiGroup名,就是""
verbs: ["get", "list"] # 获取独立的 Service (通过名字)并且列出所有允许的服务
resources: ["services"] # 这条规则和服务有关(必须使用复数的名字!)
警告 在指定资源时必须使用复数的形式 #F44336
在角色定义中,需要为定义包含的每个规则涉及的资源指定 apiGroup。如果你允许访间属于不同API组的资源,可以使用多种规则。
在本例中,你允许访 问所有服务资原,但是也可以通过额外的 resourceNames 字段指定服务实例的名称来限制对服务实例的访问。
绑定角色到 ServiceAccount
角色定义了哪些操作可以执行,但没有指定谁可以执行这些操作。要做到这一点,必须将角色绑定 一个到主体,它可以是一个user (用户)、 一个 ServiceAccount 或一个组(用户或 ServiceAccount 组)
kubectl create rolebinding test --role=service-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/test created
创建 RoleBinding 资源,它将 service-reader 角色绑定到命名空间 foo 中的 default ScrviceAccoun s上。这个 RoleBinding 资源会被创建在命名空间 foo 中。 RoleBinding 资源和 ServiceAccount角色的引用如图 所示
注意: #F44336 如果要绑定一个角色到一个 user (用户)而不是 ServiceAccount 上,---- user 作为参数来指定用户名。 如果要绑定角色到组,可以使用 -- group 参数。
[root@master rbac]# kubectl get rolebinding test -n foo -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test
namespace: foo
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role # 这个 RoleBinding 引用了service-reader Role
name: service-reader
subjects:
- kind: ServiceAccount # 并且将它绑定到 foo 名称空间中的 default ServiceAccount 上
name: default
namespace: foo
RoleBinding 始终引用单个角色(从 roleRef 属性中可以看出),但是可以将角色绑定到多个主体(例如,一个或多个 ServiceAccount 和任意数量的用户或组)上 。因为这个 RoleBinding 将角色绑定到 ServiceAccount 上,这个ServiceAccount 运行在 foo 命名空间中的 pod 上,所以现在可以列出来自 pod 中的服务。
[root@master ~]# kubectl exec -it test -n foo sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
"kind": "ServiceList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "147872"
},
"items": []
}
在角色绑定中使用其他命名空间的 ServiceAccount
[root@master ~]# kubectl exec -it test -n bar sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # curl localhost:8001/api/v1/namespaces/foo/services
...
"message": "services is forbidden: User \"system:serviceaccount:bar:default\" cannot list resource \"services\" in API group \"\" in the namespace \"foo\"",
...
/ # curl localhost:8001/api/v1/namespaces/bar/services
...
"message": "services is forbidden: User \"system:serviceaccount:bar:default\" cannot list resource \"services\" in API group \"\" in the namespace \"bar\"",
...
bar 命名空间中的 pod 不能列出自己命名空间中的服务,也不能列出 foo 命名空间中的服务。
但是可以修改在 foo 命名空间中的 RoleBinding 并添加另一个 pod ServicAccount ,即使这个 ServiceAccount 在另一个不同的命名空间中。
[root@master ]# kubectl edit rolebinding test -n foo
subjects:
- kind: ServiceAccount
name: default
namespace: foo
- kind: ServiceAccount #添加如下三行
name: default # 引用来自 bar 命名空间中的 Sefault ServiceAccount
namespace: bar
现在,就可以从运行在 bar 命名空间里的 pod 中列出 foo 命名空间中的服务。
[root@master ~]# kubectl exec -it test -n bar sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
"kind": "ServiceList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "149362"
},
"items": []
}
使用 ClusterRole 和 ClusterRoleBinding
Role 和 RoleBinding 都是命名空间的资源,这意味着它们属于和应用在一个单一的命名空间资源上。但是,RoleBinding 可以引用来自其他命名空间中的 ServiceAccount。
除了这些命名空间里的资源,还存在两个集群级别的 RBAC 资源 :
ClusterRole 和 ClusterRoleBinding,它们不在命名空间里。
为什么需要它们
一个常规的角色只允许访问和角色在同一命名空间中的资源。 如果你希望许跨不同命名空间访问资源,就必须要在每个命名空间中创建一个 Role 和RoleBinding。 如果你想将这种行为扩展到所有的命名空间(集群管理员可能需要 ),需要在每个命名空间中创建相同的 Role 和 RoleBinding。 当创建一个新的命名空间时,必须记住也要在新的命名空间中创建这两个资源。
一些特定的资源完全不在命名空间中(包括Node PersistentVolume Namespace ,等等)。 API 服务器对外暴露了一些不表示资源的路径(例如 /healthz)。 常规角色不能对这些资源或非资源型的 URL 进行授权,但是 ClusterRole 可以。
ClusterRole 是一种集群级资源,它允许访问没有命名空间的资源和非资源型的URL,或者作为单个命名空间内部绑定的公共角色,从而避免必须在每个命名在空间中重新定义相同的角色。
允许访问集群级别的资源
[root@master ~]# kubectl create clusterrole pv-reader --verb=get,list --resource=persistentvolumes
clusterrole.rbac.authorization.k8s.io/pv-reader created
[root@master ~]# kubectl get clusterrole pv-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata: # ClusteRole 不在命名空间内,所以没有命名空间字段
name: pv-reader
...
rules: # 在这个例子中,这些规则完全和正常的 Role 一样
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
将这个 ClusterRole 绑定到 pod ServiceAccount 之前,验证 pod 否可以列出 PersistentVolume 。
[root@master ~]# kubectl exec -it test -n foo sh
/ # curl localhost:8001/api/v1/persistentvolumes
...
"message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope",
...
}
需要将 ClusterRole 绑定到 ServiceAccount 来允许它这样做。ClusterRole 可以通过常规的RoleBinding (角色绑定)来和主体绑定,要创建 RoleBinding。
[root@master ~]# kubectl create rolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/pv-test created
[root@master ~]# kubectl exec -it test -n foo sh
/ # curl localhost:8001/api/v1/persistentvolumes
...
"message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope",
...
}
仍然不能列出 Persistentvolume ,检查yaml文件
[root@master ~]# kubectl get rolebindings pv-test -o yaml -n foo
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pv-test
namespace: foo
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pv-reader
subjects:
- kind: ServiceAccount
name: default
namespace: foo
尽管可以创建一个 RoleBinding 并在需要开启命名空间资源的访问时引用一个 ClusterRole ,但是不能对集群级别( 没有命名空间的)资源使用相同的方法。必须始终使用 ClusterRoleBinding 来对集群级别的资源进行授权访问。
创建 ClusterRoleBinding 和创建 RoleBinding 并没有什么太大区别,但是首先需要要清理和删除 RoleBinding:
[root@master ~]# kubectl delete rolebinding pv-test -n foo
rolebinding.rbac.authorization.k8s.io "pv-test" deleted
创建Clusterrolebinding:
[root@master ~]# kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/pv-test created
[root@master ~]# kubectl describe clusterrolebinding pv-test
Name: pv-test
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: pv-reader
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount default foo
[root@master ~]# kubectl get clusterrolebinding pv-test -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pv-test
...
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pv-reader
subjects:
- kind: ServiceAccount
name: default
namespace: foo
[root@master ~]# kubectl exec -it test -n foo sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # curl localhost:8001/api/v1/persistentvolumes
{
"kind": "PersistentVolumeList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "159548"
},
"items": []
}
现在可以列出 PersistentVolume ,这表明在授予集群级别的资源访问权限时 ,必须使用一个 ClusterRole 和一个 ClusterRoleBinding。
提示 #F44336 记住一个 RoleBinding 不能授予集群级别的资源访问权限,即使它引用了一个 ClusterRoleBinding 。
允许访问非资源型的 URL
API 服务器也会对外暴露非资源型的 URL 。访问这些 URL必须要显式地授予权限。否则, API 服务器会拒绝客户端的请求。
通常,这个会通 system:discovery ClusterRole 和相同命名的 ClusterRoleBinding 帮你自动完成,它出现在其他预定义的 ClusterRoles 和 ClusterRoleBindings 中。
查看 system:discovery 中的 ClusterRole。
[root@master ~]# kubectl get clusterrole system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: "2021-12-07T20:03:16Z"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:discovery
resourceVersion: "86"
uid: 74388c67-aef7-468c-9bd7-4e9acd5088ed
rules:
- nonResourceURLs: # 这条规则指向了非资源型的 URL 而不是资源
- /api
- /api/*
- /apis
- /apis/*
- /healthz
- /livez
- /openapi
- /openapi/*
- /readyz
- /version
- /version/
verbs: # 对于这些 URL 只有 HTTP GET 方法是被允许的
- get
注意: #F44336 对于非资源型 URL ,使用普通的 HTTP 动词,如 post put 和 patch,而不是 create update。 动词需要使用小写的形式指定。
和集群级别的资源一样,非资源型的 URL ClusterRole 必须与 ClusterRoleBinding 结合使用。把它们和 RoleBinding 绑定不会有任何效果。system:discovery ClusterRole 有一个与之对应的 system:discovery ClusterRoleBinding。
[root@master ~]# kubectl get clusterrolebinding system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: ...
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:discovery
resourceVersion: "149"
uid: 25d3d83d-bb7f-4f34-b9aa-e460bf7d2e6f
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole # Clusterrolebinding 引用了system:discovery ClusterRole
name: system:discovery
subjects: # 它将 ClusterRole 绑定到所有认证过和没有认证过的用户上
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated
YAML 内容显示 ClusterRoleBinding 正如预期的那样指向 system:discovery ClusterRole。 它绑定到了两个组, 分别是 system:authenticated 和 system:unauthenticated ,这使得它和所有用户绑定在一起。这意味着每个人都绝对可以访问列在 ClusterRole 中的 URL。
注意: 组位于身份认证插件的域中。 API 服务器接收到一个请求时, 它会调用身份认证插件来获取用户所属组的列表, 之后授权中会使用这些组的信息。
可以通过在一个 pod 内和本地机器访问 /api URL 路径来进行确认(通过 kubectl proxy ,意味着你会使用 pod 的 ServiceAccount 来进行身份认证)。 访问 URL 时不要指定任何认证的token (这会让你成为一个未认证的用户)。
/ # curl https://192.168.160.134:6443/api -k
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"",
"reason": "Forbidden",
"details": {
},
"code": 403
}
这个访问结果待定。。。
使用ClusterRole 来授权访问指定命名空间中的资源
ClusterRole 不是必须一直和集群级别的 ClusterRoleBinding 捆绑使用。 也可以和常规的有命名空间的 RoleBinding 进行捆绑。
[root@master ~]# kubectl get clusterrole view -o yaml
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: ...
labels:
kubernetes.io/bootstrapping: rbac-defaults
rbac.authorization.k8s.io/aggregate-to-edit: "true"
name: view
resourceVersion: "398"
uid: 883ab2ba-6279-4217-b319-a6a1b07605ab
rules:
- apiGroups:
- ""
resources: # 这条规则应用于这些资源上(注意它是命名空间的资源)
- configmaps
- endpoints
- persistentvolumeclaims
- persistentvolumeclaims/status
- pods
- replicationcontrollers
- replicationcontrollers/scale
- serviceaccounts
- services
- services/status
verbs: # 如 ClusterRole 名称表述的那样,它只允许读操作,不能对列出的资源进行写操作
- get
- list
- watch
...
这个 ClusterRole 有很多规则,这里只展示了第一条规则。这个规则允许 get、 list 和 watch 资源, 这些资源就像 ConfigMap 、 Endpoint、PersistentVolumeClaim,等等。 这些资源是有命名空间的, 即使我们正在了解的是一个ClusterRole (它不是一个常规的、有命名空间的角色)。
这个 ClusterRole 到底做了什么?
这取决于它是和 ClusterRoleBinding 还是和 RoleBinding 绑定(可以和其中的一个进行绑定)。 如果你创建了一个 ClusterRoleBinding 并在它里面引用了 ClusterRole,在绑定中列出的主体可以在所有命名空间中查看指定的资源。 相反, 如果你创建的是一个RoleBinding, 那么在绑定中列出的主体只能查看在 RoleBinding 命名空间中的资源。
使用这两个选项,可以看到这两种方式如何影响测试 pod 列出 pod 的能力。先了解绑定生效之前会发生什么:
/ # curl localhost:8001/api/v1/pods
"message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope",
...
/ # curl localhost:8001/api/v1/namespaces/foo/pods
"message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"foo\"",
...
第一个命令, 可以试着列出所有命名空间的 pod
第二个命令,可以试着列出在 foo 命名空间中的 pod
目前服务器都不允许你执行这些操作
创建一个 ClusterRoleBinding 并且把它绑定到 pod 的ServiceAccount 上
[root@master ~]# kubectl create clusterrolebinding view-test --clusterrole=view --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/view-test created
/ # curl localhost:8001/api/v1/namespaces/foo/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "182114"
},
"items": [
{
"metadata": {
"name": "test",
"namespace": "foo",
...
创建了一个 ClusterRoleBinding, 并且它应用在所有的命名空间上。 通过它命名空间 foo 中的 pod 也可以列出 bar 命名空间中的 pod 。
/ # curl localhost:8001/api/v1/namespaces/bar/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "182431"
},
"items": [
{
"metadata": {
"name": "test",
"namespace": "bar",
"uid": "7c82f08e-a064-429a-9629-a87e0594d66a",
"resourceVersion": "156065",
...
允许列出一个不同的命名空间中的 pod 。
/ # curl localhost:8001/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata":
...
这个 pod 可以获取集群中所有 pod 的列表。 总之,将 ClusterRoleBinding 和 ClusterRole 结合指向命名空间的资源,允许 pod 访问任何命名空间中的资源。
如果用一个 RoleBinding 替换 ClusterRoleBinding 会发生什么。
首先,删除 ClusterRoleBinding:
[root@master ~]# kubectl delete clusterrolebinding view-test
clusterrolebinding.rbac.authorization.k8s.io "view-test" deleted
创建一个 RoleBinding 作为替代。 因为 RoleBinding 使用了命名空间, 所以需要指定希望 RoleBinding 创建在里面的命名空间。 在 foo 命名空间中创建 RoleBinding:
[root@master ~]# kubectl create rolebinding view-test --clusterrole=view --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/view-test created
现在在 foo 命名空间中有一个 RoleBinding,它将在同一个命名空间中的 default ServiceAccount 绑定到 view ClusterRole。现在 foo 名称空间下的 pod 可以访问什么资源?
[root@master ~]# kubectl exec -it test -n foo sh
/ # curl localhost:8001/api/v1/namespaces/foo/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
...
/ # curl localhost:8001/api/v1/namespaces/bar/pods
"message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"bar\"",
...
/ # curl localhost:8001/api/v1/pods
"message": "pods is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope",
...
这个 pod 可以列出 foo 命名空间中的 pod,但并不是其他特定的命名空间或者所有的命名空间都能做到。
总结Role、ClusterRole、 Rolebinding 和 ClusterRoleBinding的组合
了解默认的 ClusterRole 和 ClusterRoleBinding
Kubernetes 提供了一组默认的 ClusterRole 和 ClusterRoleBinding, 每次 API 服务器启动时都会更新它们。 这保证了在你错误地删除角色和绑定, 或者 Kubernetes 的新版本使用了不同的集群角色和绑定配置时, 所有的默认角色和绑定都会被重新创建。
[root@master ~]# kubectl get clusterrolebindings
NAME ROLE AGE
cluster-admin ClusterRole/cluster-admin 7d22h
flannel ClusterRole/flannel 7d22h
kubeadm:get-nodes ClusterRole/kubeadm:get-nodes 7d22h
kubeadm:kubelet-bootstrap ClusterRole/system:node-bootstrapper 7d22h
kubeadm:node-autoapprove-bootstrap ClusterRole/system:certificates.k8s.io:certificatesigningrequests:nodeclient 7d22h
kubeadm:node-autoapprove-certificate-rotation ClusterRole/system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 7d22h
kubeadm:node-proxier ClusterRole/system:node-proxier 7d22h
pv-test ClusterRole/pv-reader 6h41m
system:basic-user ClusterRole/system:basic-user 7d22h
system:controller:attachdetach-controller ClusterRole/
...
system:volume-scheduler ClusterRole/system:volume-scheduler 7d22h
[root@master ~]# kubectl get clusterroles
NAME CREATED AT
admin 2021-12-07T20:03:16Z
cluster-admin 2021-12-07T20:03:16Z
edit 2021-12-07T20:03:16Z
flannel 2021-12-07T20:03:20Z
kubeadm:get-nodes 2021-12-07T20:03:18Z
pv-reader 2021-12-14T12:01:08Z
system:aggregate-to-admin 2021-12-07T20:03:16Z
system:aggregate-to-edit 2021-12-07T20:03:16Z
...
system:service-account-issuer-discovery 2021-12-07T20:03:16Z
system:volume-scheduler 2021-12-07T20:03:16Z
view 2021-12-07T20:03:16Z
view、 edit、 admin 和 cluster-adrnin ClusterRole是最重要的角色, 它们应该绑定到用户定义 pod 中的 ServiceAccount 上。
用view ClusterRole 允许对资源的只读访问
前面使用了默认的 view ClusterRole, 它允许读取一个命名空间中的大多数资源, 除了Role、 RoleBinding和 Secret。
为什么 Secrets 不能被读取?因为 Secrets 中的某一个可能包含一个认证 token, 它比定义在
view ClusterRole 中的资源有更大的权限 ,并且允许用户伪装成不同的用户来获取额外的权限(权限扩散)。
用 editClusterRole 允许对资源的修改
接下来是 edit ClusterRole, 它允许你修改一个命名空间中的资源, 同时允许读取和修改 Secret。 但是, 它也不允许查看或修改 Role 和 RoleBinding, 这是为了防止权限扩散。
用adminClusterRole赋予一个命名空间全部的控制权
一个命名空间中的资源的完全控制权是由 admin ClusterRole 赋予的。 有这个 ClusterRole 的主体可以读取和修改命名空间中的任何资源, 除了 ResourceQuota 和命名空间资源本身。 edit 和admin ClusterRole 之间的主要区别是能否在命名空间中查看和修改 Role 和 RoleBinding。
注意: 为了防止权限扩散, API 服务器只允许用户在已经拥有一个角色中列出的所有权限(以及相同范围内的所有权限)的情况下, 创建和更新这个角色。
用 cluster-admin ClusterRole 得到完全的控制
通过将 cluster-admin ClusterRole 赋给主体, 主体可以获得 Kubernetes 集群完全控制的权限。 正如你前面了解的那样, admin ClusterRole 不允许用户修改命名空间的 ResourceQuota 对象或者命名空间资源本身。 如果你想允许用户这样做, 需要创建一个指向 cluster-admin ClusterRole的 RoleBinding。 这使得 RoleBinding 中包含的用户能够完全控制创建 RoleBinding 所在命名空间上的所有方面 。