kubernetes/MD/kubernetes-RBAC.md

745 lines
24 KiB
Markdown
Raw Normal View History

2023-10-29 13:36:59 +08:00
<h1><center>kubernetes-RBAC</center></h1>
著作:行癫 <盗版必究>
------
## 一RBAC详解
#### 1.RBAC基于角色的访问控制
Service Account为服务提供了一种方便的认证机制但它不关心授权的问题。可以配合RBAC来为Service Account鉴权,在Kubernetes中授权有ABAC基于属性的访问控制、RBAC基于角色的访问控制、Webhook、Node、AlwaysDeny一直拒绝和AlwaysAllow一直允许这6种模式
从1.6版起Kubernetes 默认启用RBAC访问控制策略
从1.8开始RBAC已作为稳定的功能
#### 2.授权步骤
定义角色:在定义角色时会指定此角色对于资源的访问控制的规则
绑定角色:将主体与角色进行绑定,对用户进行访问授权
基于角色的访问控制使用"rbac.authorization.k8s.io" API Group实现授权决策允许管理员通过Kubernetes API动态配置策略
定义Role、ClusterRole、RoleBinding或ClusterRoleBinding
#### 3.启用RBAC
要启用RBAC使用--authorization-mode=RBAC启动API Server
```shell
[root@master ~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.18.160:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.18.160
- --allow-privileged=true
- --authorization-mode=Node,RBAC
```
#### 4.Role与ClusterRole
一个角色包含了一套表示一组权限的规则。 权限以纯粹的累加形式累积(没有"否定"的规则)
###### Role
角色可以由命名空间内的Role对象定义
一个Role对象只能用于授予对某一单一命名空间中资源的访问权限
###### ClusterRole
整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现
###### Role示例
描述"default"命名空间中的一个Role对象的定义用于授予对pod的读访问权限
```shell
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]       # 空字符串""表明使用core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
```
注意:
watch操作语义的含义如下读取状态并从任意版本开始
在任何资源版本开始 watch首选可用的最新资源版本但不是必需的。允许任何起始资源版本。由于分区或过时的缓存watch 可能从客户端之前观察到的更旧的资源版本开始,特别是在高可用性配置中。不能容忍这种明显倒带的客户不应该用这种语义启动 watch。 为了建立初始状态watch从起始资源版本中存在的所有资源实例的合成 “添加” 事件开始。 以下所有监视事件都针对在watch开始的资源版本之后发生的所有更改
**读取状态并从最新版本开始**
从最近的资源版本开始 **watch** 它必须是一致的(详细说明:通过仲裁读取从 etcd 提供服务)。 为了建立初始状态,**watch** 从起始资源版本中存在的所有资源实例的合成 “添加” 事件开始。 以下所有监视事件都针对在 **watch** 开始的资源版本之后发生的所有更改
**从指定版本开始**
以确切的资源版本开始 **watch**。监视事件适用于提供的资源版本之后的所有更改。 与 “Get State and Start at Most Recent” 和 “Get State and Start at Any” 不同, **watch** 不会以所提供资源版本的合成 “添加” 事件启动。 由于客户端提供了资源版本,因此假定客户端已经具有起始资源版本的初始状态
###### ClusterRole示例
ClusterRole定义可用于授予用户对某一特定命名空间或者所有命名空间中的secret取决于其绑定方式的读访问权限
```shell
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# ClusterRole是集群范围对象所以这里不需要定义"namespace"字段
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
#### 5.RoleBinding与ClusterRoleBinding
角色绑定将一个角色中定义的各种权限授予一个或者一组用户
###### 角色绑定包含:
一组相关主体, 即:subject
包括:
用户--User
用户组--Group
服务账户--Service Account
对被授予角色的引用
###### RoleBinding
在命名空间中可以通过RoleBinding对象授予权限
RoleBinding可以引用在同一命名空间内定义的Role对象
###### ClusterRoleBinding
集群范围的权限授予则通过ClusterRoleBinding对象完成
###### RoleBinding示例
定义的RoleBinding对象在"default"命名空间中将"pod-reader"角色授予用户"jane"。 这一授权将允许用户"jane"从"default"命名空间中读取pod以下角色绑定定义将允许用户"jane"从"default"命名空间中读取pod
```shell
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User          #赋予用户jane pod-reader角色权限
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader      #引用上面定义的role
apiGroup: rbac.authorization.k8s.io
```
RoleBinding对象也可以引用一个ClusterRole对象
用于在RoleBinding所在的命名空间内授予用户对所引用的ClusterRole中定义的命名空间资源的访问权限
这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色
例如尽管下面示例中的RoleBinding引用的是一个ClusterRole对象但是用户"dave"(即角色绑定主体)还是只能读取"development" 命名空间中的secret即RoleBinding所在的命名空间
以下角色绑定允许用户 "dave" 读取 "development" 命名空间中的secret
```shell
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets
namespace: development       # 这里表明仅授权读取"development"命名空间中的资源。
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader      #引用上面定义的clusterRole 名称clusterRole没有指定命名空间默认可以应用所有但是在rolebinding时指定了命名空间所以只能读取本命名空间的文件
apiGroup: rbac.authorization.k8s.io
```
ClusterRoleBinding在集群级别和所有命名空间中授予权限
以下 'ClusterRoleBinding' 对象允许在用户组 "manager" 中的任何用户都可以读取集群中任何命名空间中的secret
```shell
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
```
#### 6.role对资源的引用
大多数资源由代表其名字的字符串表示,如 "pods"就像它们出现在相关API endpoint的URL中一样。然而有一些Kubernetes API还包含了 "子资源"
比如pod的logs:
pod logs endpoint的URL格式为
GET /api/v1/namespaces/{namespace}/pods/{name}/log
这种情况下,"pods" 是命名空间资源,而 "log" 是pods的子资源
为了在RBAC角色中表示出这一点需使用斜线来划分 资源 与 子资源
例子:
如果需要角色绑定主体读取pods以及pod log需要定义以下角色
```shell
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]    #表示授予读取pods下log的权限
verbs: ["get", "list"]
```
###### resourceNames
通过 resourceNames 列表角色可以针对不同种类的请求根据资源名引用资源实例。当指定了resourceNames 列表时,不同动作种类的请求的权限,如使用 "get"、"delete"、"update" 以及 "patch" 等动词的请求,将被限定到资源列表中所包含的资源实例上
例子:
如果需要限定一个角色绑定主体只能 "get" 或者 "update" 一个configmap时可以定义以下角色
```shell
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
resources: ["configmap"]
resourceNames: ["my-configmap"]
verbs: ["update", "get"]
```
注意:
如果设置了resourceNames则请求所使用的动词不能是list、watch、create或者deletecollection由于资源名不会出现在create、list、watch和deletecollection等API请求的URL中所以这些请求动词不会被设置了resourceNames 的规则所允许因为规则中的resourceNames部分不会匹配这些请求
###### 角色定义的例子:
在以下示例中仅截取展示了rules部分的定义
允许读取core API Group中定义的资源 "pods"
```shell
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
```
允许读写在 "extensions" 和 "apps" API Group中定义的 "deployments"
```shell
rules:
- apiGroups: [""]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
```
允许读取 "pods" 以及读写 "jobs"
```shell
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch", "extensions"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
```
允许读取一个名为 "my-config" 的 ConfigMap 实例
```shell
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["my-config"]
verbs: ["get"]
```
允许读取core API Group中的"nodes"资源Node是集群级别资源所以此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效
```shell
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
```
允许对非资源endpoint "/healthz" 及其所有子路径的 "GET" 和 "POST" 请求
```shell
rules:
- nonResourceURLs: ["/healthz", "/healthz/*"]   # 在非资源URL中'*'代表后缀通配符
verbs: ["get", "post"]
注意:
此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效
```
#### 7.对角色绑定主体Subject的引用
RoleBinding或者ClusterRoleBinding将角色绑定到角色绑定主体Subject。 角色绑定主体kind指定可以是用户组Group、用户User或者服务账户Service Accounts
###### 用户:
由字符串表示
纯粹的用户名,例如 "alice"
电子邮件风格的名字,如 "bob@example.com"
用字符串表示的数字id
用户的产生:
由Kubernetes管理员配置认证模块以产生所需格式的用户名。对于用户名RBAC授权系统不要求任何特定的格式
注意:
前缀system:是 为Kubernetes系统使用而保留的所以管理员应该确保用户名不会意外地包含这个前缀
用户组的产生:
Kubernetes中的用户组信息由授权模块提供。用户组与用户一样由字符串表示。Kubernetes对用户组 字符串没有格式要求但前缀system:同样是被系统保留的
服务账户:
服务账户serviceAccount拥有包含 system:serviceaccount:前缀的用户名并属于拥有system:serviceaccounts:前缀的用户组
###### 角色绑定例子:
以下示例中仅截取展示了RoleBinding的subjects字段
一个名为"alice@example.com"的用户
```shell
subjects:
- kind: User
name: "alice@example.com"
apiGroup: rbac.authorization.k8s.io
```
一个名为"frontend-admins"的用户组
```shell
subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
```
kube-system命名空间中的默认服务账户
```shell
subjects:
- kind: ServiceAccount
name: default
namespace: kube-system
```
名为"qa"命名空间中的所有服务账户
```shell
subjects:
- kind: Group
name: system:serviceaccounts:qa
apiGroup: rbac.authorization.k8s.io
```
在集群中的所有服务账户
```shell
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
```
所有认证过的用户version 1.5+
```shell
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
```
所有未认证的用户version 1.5+
```shell
subjects:
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
```
所有用户version 1.5+
```shell
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
```
#### 8.默认角色与默认角色绑定
API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象。 这些默认对象中有许多包含system:前缀表明这些资源由Kubernetes基础组件"拥有"。 对这些资源的修改可能导致非功能性集群non-functional cluster
比如system:node ClusterRole对象。 这个角色定义了kubelets的权限。如果这个角色被修改可能会导致kubelets无法正常工作
所有默认的ClusterRole和ClusterRoleBinding对象都会被标记为kubernetes.io/bootstrapping=rbac-defaults
每次启动时API Server都会更新默认ClusterRole所缺乏的各种权限并更新默认ClusterRoleBinding所缺乏的各个角色绑定主体。 这种自动更新机制允许集群修复一些意外的修改。由于权限和角色绑定主体在新的Kubernetes释出版本中可能变化这也能够保证角色和角色绑定始终保持是最新的
如果需要禁用自动更新请将默认ClusterRole以及ClusterRoleBinding的rbac.authorization.kubernetes.io/autoupdate 设置成为false。 请注意,缺乏默认权限和角色绑定主体可能会导致非功能性集群问题
自Kubernetes 1.6+起当集群RBAC授权器RBAC Authorizer处于开启状态时可以启用自动更新功能
###### 命令行工具:
有两个kubectl命令可以用于在命名空间内或者整个集群内授予角色
```shell
[root@master ~]# kubectl create rolebinding
```
在某一特定命名空间内授予Role或者ClusterRole
示例如下:
在名为"acme"的命名空间中将admin ClusterRole授予用户"bob"
```shell
[root@master ~]# kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
```
在名为"acme"的命名空间中将view ClusterRole授予服务账户"myapp"
```shell
[root@master ~]# kubectl create rolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme
```
在整个集群中授予ClusterRole包括所有命名空间示例如下
在整个集群范围内将cluster-admin ClusterRole授予用户"root"
```shell
[root@master ~]# kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
```
在整个集群范围内将system:node ClusterRole授予用户"kubelet"
```shell
[root@master ~]# kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet
```
在整个集群范围内将view ClusterRole授予命名空间"acme"内的服务账户"myapp"
```shell
[root@master ~]# kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp
```
#### 9.服务账户Service Account权限
默认的RBAC策略将授予控制平面组件control-plane component、节点node和控制器controller一组范围受限的权限 但对于"kube-system"命名空间以外的服务账户,则不授予任何权限(超出授予所有认证用户的发现权限)
从最安全到最不安全可以排序以下方法:
对某一特定应用程序的服务账户授予角色(最佳实践)
要求应用程序在其pod规范pod spec中指定serviceAccountName字段并且要创建相应服务账户例如通过API、应用程序清单或者命令kubectl create serviceaccount等
###### 案例:
在"my-namespace"命名空间中授予服务账户"my-sa"只读权限
```shell
[root@master ~]# kubectl create rolebinding my-sa-view \
--clusterrole=view \
--serviceaccount=my-namespace:my-sa \
--namespace=my-namespace
```
换成yaml文件大概如下
```shell
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: my-sa-view
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-sa
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view #这里view为clusterrole名称其中berbs需要给view
apiGroup: rbac.authorization.k8s.io
```
在某一命名空间中授予"default"服务账号角色
如果一个应用程序没有在其pod规范中指定serviceAccountName它将默认使用"default"服务账号
注意:授予"default"服务账号的权限将可用于命名空间内任何没有指定serviceAccountName的pod
例子:
下面的例子将在"my-namespace"命名空间内授予"default"服务账号只读权限
```shell
[root@master ~]# kubectl create rolebinding default-view \
--clusterrole=view \
--serviceaccount=my-namespace:default \
--namespace=my-namespace
```
目前许多加载项addon作为"kube-system"命名空的"default"服务帐户运行。 要允许这些加载项使用超级用户访问权限请将cluster-admin权限授予"kube-system"命名空间中的"default"服务帐户。 注意:启用上述操作意味着"kube-system"命名空间将包含允许超级用户访问API的秘钥
```shell
[root@master ~]# kubectl create clusterrolebinding add-on-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:default
```
为命名空间中所有的服务账号授予角色
如果希望命名空间内的所有应用程序都拥有同一个角色,无论它们使用什么服务账户,可以为该命名空间的服务账户用户组授予角色
例子:
下面的例子将授予"my-namespace"命名空间中的所有服务账户只读权限
```shell
[root@master ~]# kubectl create rolebinding serviceaccounts-view \
--clusterrole=view \
--group=system:serviceaccounts:my-namespace \
--namespace=my-namespace
```
## 二RBAC应用
创建k8s账号与RBAC授权使用
#### 创建账号
创建私钥
```shell
[root@master ~]# (umask 077; openssl genrsa -out xingdian.key 2048)
```
用此私钥创建一个csr(证书签名请求)文件
```shell
[root@master ~]# openssl req -new -key xingdian.key -out xingdian.csr -subj "/CN=xingdian"
[root@master ~]# openssl x509 -req -in xingdian.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out xingdian.crt -days 365
```
看证书内容
```shell
[root@master ~]# openssl x509 -in xingdian.crt -text -noout
[root@master ~]# kubectl config set-credentials xingdian --client-certificate=./xingdian.crt --client-key=./xingdian.key --embed-certs=true
```
设置上下文(设置为k8s集群的用户)
```shell
[root@master ~]# kubectl config set-context xingdian@kubernetes --cluster=kubernetes --user=xingdian
```
查看当前的工作上下文
```shell
[root@master ~]# kubectl config view
```
切换用户(切换上下文)
```shell
[root@master ~]# kubectl config use-context xingdian@kubernetes
```
验证是否已经切换到了新的上下文
```shell
[root@master ~]# kubectl config current-context
```
测试(还未赋予权限)
```shell
[root@master ~]# kubectl get pod
No resources found.
Error from server (Forbidden): pods is forbidden: User "wing" cannot list pods in the namespace "default"
```
#### 授权
K8S授权请求是http的请求
对象URL格式
/apis/[GROUP]/[VERSION]/namespace/[NAMESPACE_NAME]/[KIND]/[OBJECT_ID]
k8s授权方式分为
serviceaccount和自己签证ca证书的账号及签证ca的用户组group授权给这个组的权限
role
允许的操作如get,list等
允许操作的对象如pod,svc等
rolebinding
将哪个用户绑定到哪个role或clusterrole上
clusterrole(集群角色)
clusterrolebinding:(绑定到集群)
如果使用rolebinding绑定到role上表示绑定的用户只能用于当前namespace的权限
###### 创建一个角色:
切回管理帐号先
```shell
[root@master ~]# kubectl config use-context kubernetes-admin@kubernetes
[root@master ~]# kubectl create role myrole --verb=get,list,watch --resource=pod,svc
```
绑定用户xingdian绑定role为myrole
```shell
[root@master ~]# kubectl create rolebinding myrole-binding --role=myrole --user=xingdian
```
切换用户
```shell
[root@master ~]# kubectl config use-context xingdian@kubernetes
Switched to context "xingdian@kubernetes".
```
查看权限
只授权了default名称空间pod和svc的getlistwatch权限
```shell
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-pod 0/1 ImagePullBackOff 0 1h
[root@master ~]# kubectl get pod -n kube-system #无权访问kube-system
No resources found.
Error from server (Forbidden): pods is forbidden: User "wing" cannot list pods in the namespace "kube-system"
[root@master ~]# kubectl delete pod nginx-pod #无删除权限
Error from server (Forbidden): pods "nginx-pod" is forbidden: User "wing" cannot delete pods in the namespace "default"
```
###### 创建clusterrole
可以访问全部的namespace
```shell
[root@master ~]# kubectl create clusterrole mycluster-role --verb=get,list,watch --resource=pod,svc
```
删除xingdian账号之前绑定的rolebinding
```shell
[root@master ~]# kubectl delete rolebinding myrole-binding
```
使用clusterrolebinding绑定clusterrole
```shell
[root@master ~]# kubectl create clusterrolebinding my-cluster-rolebinding --clusterrole=mycluster-role --user=xingdian
```
切换账号
```shell
[root@master ~]# kubectl config use-context xingdian@kubernetes
```
查看权限 查看kube-system空间的pod
```shell
# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-78fcdf6894-67h9h 1/1 Running 1 11h
coredns-78fcdf6894-lzxmz 1/1 Running 1 11h
etcd-k8s-m 1/1 Running 2 11h
......
```