RBAC 之所以一直没有写这个,一方面是因为它确实并不复杂,二来平常确实接触不多,今天就来顺路讲讲它
定义
Role-Based Access Control 我们常说的 RBAC,我们知道在一个后台管理系统里面经常会有权限管理。而最常用的一种权限设计方式就是基于角色的权限设计,A 用户是管理员拥有所有的权限,B 是普通用户角色只有部分权限等等,而 k8s 也是如此,k8s 内部也有许许多多的资源,通过 RBAC 的权限设计进行管理授权工作。
- Role: 角色,定义了一组对 Kubernetes API 对象的操作权限
- Subject: 用户,绑定角色的对象
- RoleBinding: 用户和角色的绑定关系
其实非常好理解: 用户 -> 角色 -> 权限
Role
1 2 3 4 5 6 7 8 9
| apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
|
这就是 k8s 里面的角色,这里定义了一个角色 pod-reader 这个角色可以对 default 命名空间中的 pod 资源进行 get watch list 操作
ClusterRole
1 2 3 4 5 6 7 8 9 10
| apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: secret-reader rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "watch", "list"]
|
ClusterRole 属于集群范围,所以整个集群对应的资源都可以被使用
RoleBinding
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding metadata: name: read-pods namespace: default subjects:
- kind: User name: jane apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
|
有了角色自然就是将用户绑定到对应的角色上去了,这个没有什么好说的,很容易理解
ClusterRoleBinding
1 2 3 4 5 6 7 8 9 10 11 12 13
| apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding 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
|
同样的 ClusterRoleBinding 也是类似
ServiceAccount
其实 User 不多,其实我们更多的使用 k8s 里的内置用户也就是 ServiceAccount,这个 ServiceAccount 会生成一个 secrets 利用这个可以跟 APIServer 进行交互
1 2 3 4 5
| apiVersion: v1 kind: ServiceAccount metadata: namespace: mynamespace name: example-sa
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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
|
1 2 3 4 5 6 7 8 9 10
| apiVersion: v1 kind: Pod metadata: namespace: mynamespace name: sa-token-test spec: containers: - name: nginx image: nginx:1.7.9 serviceAccountName: example-sa
|
通过 serviceAccountName 指定对应的 ServiceAccount 就可以使用了
通过 client-go 来使用
如果只是上面那样有点空,也有点虚,不如直接开官网文档来的快。下面就直接使用实际的案例来看看 rbac 到底是怎么样作用的。
目标
我们的目标是创建一个用户,然后绑定对应的权限,有了对应的权限之后,创建的对应的 deployment 使用对应的用户,然后获取到对应的资源,我们使用 client-go 直接获取对应的资源信息看看。
创建用户
这里我们使用 ClusterRole,并且直接绑定已有的角色 cluster-admin, 然后创建需要使用的 ServiceAccount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: admin annotations: rbac.authorization.kubernetes.io/autoupdate: "true" roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: admin namespace: my-namespace --- apiVersion: v1 kind: ServiceAccount metadata: name: admin namespace: my-namespace labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile
|
一个简单的 client-go 应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| package main
import ( "context" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" )
func main() { config, err := rest.InClusterConfig() if err != nil { panic(err.Error()) }
clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err.Error()) }
fmt.Printf("all namespaces: ") nsList, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) if err != nil { panic(err.Error()) } for _, item := range nsList.Items { fmt.Printf("%s ", item.Name) }
fmt.Println() fmt.Printf("all deployments in default namespace: ") deployments, err := clientset.AppsV1().Deployments("default").List(context.TODO(), metav1.ListOptions{}) if err != nil { panic(err.Error()) } for _, item := range deployments.Items { fmt.Printf("%s ", item.Name) }
select {} }
|
因为我们的应用运行在 k8s 内部,所以使用 client-go 非常容易,使用 rest.InClusterConfig() 就可以获取到对应配置
只要当前 deployment 有对应的权限,就可以获取到对应的资源 pod 或者 namespace 等
创建 deployment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: apps/v1 kind: Deployment metadata: name: rabc-test namespace: my-namespace labels: app: rabc-test spec: replicas: 1 selector: matchLabels: app: rabc-test template: metadata: labels: app: rabc-test spec: containers: - name: rabc-test image: linkinstars.com/rabc-test:latest serviceAccountName: admin
|
创建 deployment 使用 serviceAccountName 指定刚才创建的 ServiceAccount admin 这里需要注意缩进,它是 template 下的 spec 的一个属性
运行后查看日志则可以获取到对应的所有的 namespace 列表和 default 下的所有 deployment
总结
参考文档:https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/