讲解了很多的Kubernetes内置的编排对象,以及对应的控制器模式的实现原理,此外,还剖析了自定义API资源类型和控制器的编写方式
那么能否编写一个自己的编排对象
这是必然可以的,也是Kubernetes项目中最吸引人的
Kubernetes内置的编排对象,很难做到完全的满足所有需求,很多实际的容器化工作,都要求设计一个自己的编排对象,实现自己的控制器模式
在Kubernetes项目中,基于插件机制来完成这些工作,不需要修改任何一行的代码
在编写自己的API对象之前,需要先了解RBAC
在Kubernetes中,所有API对象,都保存在Etcd中,不过,对这些API对象的操作,都是通过访问kube-apiserver来实现的,所以需要APIServer来实现授权操作
而APIServer中完成授权的工作机制,就是RBAC Role-Based Access Control
如果直接查看Kubernetes项目中关于RBAC的细节,可能有点复杂,不过,基本的概念不难,分为了Role角色,其实是一组规则,定义了一组规则,对应着K8S的操作权限
Subject 被作用者,可以是人,可以是机器,可以是Kubernetes中定义的用户
RoleBinding,定义了被作用者,角色的绑定关系
这几个概念,正是RBAC体系的核心所在
首先是Role的概念
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对象指定了能够产生作用的Namespace是mynamespace,Namespace是Kuberenetes中的一个逻辑管理单位,不同Namespace的API对象,在kubectl 操作时候,是互相隔离的
比如kubectl get pods -n mynamespace
当然,只限于逻辑上的隔离,Namespace并不会提供真正的隔离或者租户能力
在这个Role 的 rules字段,使用的就是其定义的权限规则,这条规则就是允许被作用者可以对mynamespace下的所有Pod,进行GET WATCH LIST操作
那么这个规则如何和具体的被作用者挂钩的呢?这就需要RoleBinding来实现了
RoleBing本身就是一个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对象,部署和创建Kuberenetes的流程,也不需要User
这个User从何而来
这个Kuberenetes中的User,就是用户,只是一个授权系统中的逻辑概念,通过外部认证服务,比如keystone,来提供,也可以直接给APIServer指定一个用户名,但是大多数的情况下,我们只需要使用Kubernetes中提供的内置用户,就够了
我们通过一个roleRef字段,来利用名字,绑定了Subject和Role之间的关系
而Role 和 RoleBinding对象都是Namespaced对象,对权限的限制规则也只对自己的Namesapce中有效,roleRef只能引用当前Namesapce的Role对象
对于非Namespaced的对象,诸如Node,或者某一个Role想要作用于所有Namepsace中,如何办呢
这就需要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”]
与之对应的RoleBinding,可以是ClusterRoleBinding
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-Role用户,拥有对所有Namesapce中的Pod进行GET WATCH LIST的操作权限
目前可选的权限有
verbs: [“get”, “list”, “watch”, “create”, “update”, “patch”, “delete”]
Role对象的rules字段也可以进一步的细化,比如,针对某一对象的权限进行设置
rules:
– apiGroups: [“”]
resources: [“configmaps”]
resourceNames: [“my-config”]
verbs: [“get”]
大多数时候,都不太实用用户这个功能,直接使用Kuberentes中的内置用户
这个Kuberenetes负责管理的内置用户,正是我们提到打过的ServerAccount
那么这个ServerAccount,可以看做就是我们的Role,定义的yaml如下
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: mynamespace
name: example-sa
一个最简单的ServiceAccount对象只需要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字段的类型,不是一个user,而是ServiceAccount,名为example-sa,而绑定的Role对象,依然是example-role,这是一开始定义的Role对象
然后进行创建这三个对象
$ 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
会自动分配一个sercet对象,这个sectet,就是ServiceAccount对应的,和APIServer进行交互的授权文件,称为Token,Token文件的内容一般是证书或者密码,以一个Secret的对象方式保存在ETCD
这时候,用户的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的token,就是一个Secret对象,被挂载到了容器的 /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 -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,Kubernetes会在它Namepsaace下创建一个default的默认的ServiceAccount,然后分配给这个Pod
默认情况下,这个ServiceAccout没有关联任何Role,也就说,有访问APIServer的大多数权限,当然,使用的Token还是需要ServiceAccount对应的Secret对象提供的,其类型是kubernetes.io/service-accout-token,对应的annotation,字段,声明了kubernetes.io/service-account.name=default,这个secret会跟Namespace下名为default的serviceAccout进行绑定
所以,在生产环境下,还是为所有的Namespace下的默认ServiceAccout 绑定一个只读的Role
除了之前的用户的概念,Kubernetes还拥有用户组的概念,就是一组用户的概念,如果需要配置外部认证服务的话,这个 用户组的概念就会由外部认证服务提供
对于Kubernetes的内置用户来说,用户组的概念也适用
一个ServiceAccount,在Kubernetes中对应的用户的名称为
system:serviceaccount:<Namespace名字>:<ServiceAccount名字>
对应的用户组,就是
system:serviceaccounts:<Namespace名字>
接下来看在RoleBinding里定义的subjects
subjects:
– kind: Group
name: system:serviceaccounts:mynamespace
apiGroup: rbac.authorization.k8s.io
说明了这个Role的权限规则,作用于mynamesapce中所有的ServiceAccount,这就是用户组的概念
subjects:
– kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
这样,就作用于整个系统中所有的ServiceAccount
在Kubernetes中,还内置了很多为系统保留的ClusterRole,名字都以system:开头
可以通过kubectl get clusterroles来看到
这些系统ClusterRole,是绑定给Kubernetes系统组件的ServiceAccount使用的
比如,其中一个名为system:kube-scheduler的ClusterRole,定义的权限规则是kube-scheduler所需要的权限,可以看这个权限的列表
$ kubectl describe clusterrole system:kube-scheduler
Name: system:kube-scheduler
…
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
——— —————– ————– —–
…
services [] [] [get list watch]
replicasets.apps [] [] [get list watch]
statefulsets.apps [] [] [get list watch]
replicasets.extensions [] [] [get list watch]
poddisruptionbudgets.policy [] [] [get list watch]
pods/status [] [] [patch update]
这个System:kube-scheduleer的ClusterRole,就会绑定给kube-system Namespace下名为kube-scheduler的serviceAccount,正是Kubernetes调度器的Pod声明的serviceAccount
除此外,Kubernetes还提供了四个预先定义好的ClusterRole 来供用户直接使用
1.cluster-admin
2.admin
3.edit
4.view
通过它们的名字,可以确立了它们定义了哪些权限,view权限的ClusterRole,就规定了被作绑定者只具有Kubernetes API的只读权限
cluster-admin的角色,是整个kubernetes项目中的最高权限,可以拥有全部的权限
$ kubectl describe clusterrole cluster-admin -n kube-system
Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate=true PolicyRule: Resources Non-Resource URLs Resource Names Verbs ——— —————– ————– —– *.* [] [] [*] [*] [] [*] |
所以,对于cluster-admin的使用请务必小心
在本篇文章中,主要是关于了角色的访问控制
其实Role,就是一组的权限规则的列表,我们分配这些权限的方式,就是通过创建RoleBinding对象,将被作用者和权限列表进行绑定
但是这种的切换方式只能对于nameSpace级别的控制,如果想要突破这个限制,可以使用ClusterRole和ClusterRoleBinding,是Kuberentes集群级别的Role和RoleBinding
而且权限的被作俑者不只是User,还有着ServiceAccount 和 Group,并且,常见于Role+RoleBinding+ServiceAccount这种权限分配方式
那么如何为Namespace下的默认ServiceAccount 绑定一个只读Role呢?
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: readonly-all-default
subjects:
– kind: ServiceAccount
name: default
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io