前言
有一些k8s基础的同学都知道,Kubernetes中所有的API对象,都保存到Etcd里。对这些API对象的操作却 一定是通过访问kube-apiserver实现的,其中最重要的原因就是需要apiserver来完成授权工作。负责完成授权 工作的机制,就是RBAC,基于角色的权限控制。
RBAC
使用过程
概念虽然有些复杂,但是使用起来还是相对简单的,大概下面三步:
-
在集群中创建一些角色,并为这些角色赋予相应的权限
-
将创建的角色绑定到某个账号上
-
将账号赋予Pod使用 在K8s中控制角色的对象是Role和ClusterRole,账号是ServiceAccount,而负责将角色和账号 进行绑定的动作定义到了RoleBinding和ClusterRoleBinding对象。
Role和ClusterRole的区别:
- Role对象只在某个命名空间下生效
- ClusterRole对象在整个集群范围内生效。
- RoleBinding和ClusterRoleBinding也是 这样的。
Role
我们看看Role定义案例:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: nginx
name: pod-reader
rules:
- apiGroups: [""] # core API组
resources: ["pods"]
verbs: ["get", "watch", "list"]
这个Role对象指定了产生作用的namespace:nginx。 rules 字段,就是它所定义的权限规则。在上面的例子里,这条规则的含义就是:允许“被作用者”,对 nginx 下面的 Pod 对象,进行 GET、WATCH 和 LIST 操作。
RoleBinding
我们看看RoleBinding定义案例:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-readerbinding
namespace: nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
subjects:
- kind: User
name: gitlab-runner
apiGroup: rbac.authorization.k8s.io
我们可以看到roleRef字段,正是通过这个字段,RoleBinding对象就可以直接通过名字来引用我们前面 定义的Role对象,从而定义的被作用者(subject)和角色(Role)之间的绑定关系。
注意:Role和RoleBinding对象,它们对权限的限制规则仅在它们自己的Namespace内有效,roleRef也只能引用当前Namespace里的Role对象。
我们还可以看到subjects字段,它的类型是User,即Kubernetes里的用户,这个用户的名字是gitlab-runner。 但是在Kubernetes中并没有User对象,那这个User从哪里来呢?
它需要通过外部认证服务,比如 Keystone,来提供。或者,你也可以直接给 APIServer 指定一个用户名、密码文件。那么 Kubernetes 的授权系统,就能够从这个文件里找到对应的“用户”了。
ClusterRole、ClusterRoleBinding
这就容易了,前面提到和Role的区别就是,不用指定命名空间。我们来看案例:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader
rules:
- apiGroups: [""] # core API组
resources: ["pods"]
verbs: ["get", "watch", "list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-readerbinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pod-reader
subjects:
- kind: User
name: gitlab-runner
apiGroup: rbac.authorization.k8s.io
这个例子是ClusterRole 和 ClusterRoleBinding 的组合,意味着gitlab-runner这个用户拥有 对所有命名空间里的Pod进行GET、WATCH和LIST操作的权限。
能够对API对象进行的所有操作
除了上面提到的get、watch、list,还有create、update、patch、delete
resources
需要操作的资源对象类型列表,例 如"pods"、"deployments"、"jobs"等。
apiGroups
资源对象API组列表,例 如""(Core)、"extensions"、"apps"、"batch"等。
rules字段细化控制
先看个案例:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader
rules:
- apiGroups: [""] # core API组
resources: ["configmaps"]
resourceNames: ["my-config"]
verbs: ["get"]
这里我们指定了resourceNames,表面只有对名叫"my-config"的ConfigMap对象进行get操作权限.
ServiceAccount
上面的案例我们指定subjects的类型为User,但是工作中多数情况下不使用用户这个功能,而是直接 使用Kubernetes里的“内置用户”,这个由Kubernetes负责管理的内置用户,就是ServiceAccount。
我们来看案例:
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-user
namespace: nginx
可以看到ServiceAccount的定义很简单,需要注意的是,与Role对象一样需要指定命名空间。 接下来,就可以通过ClusterRoleBinding来绑定他们。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-readerbinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pod-reader
subjects:
- kind: ServiceAccount
name: nginx-user
namespace: nginx
可以看到subjects 字段的类型变为了ServiceAccount且名字是nginx-user。
使用kubectl命令创建ClusterRole、ServiceAccount、ClusterRoleBinding对象
执行如下命令:
kubectl apply -f cluster-role.yaml
kubectl apply -f service-account.yaml
kubectl apply -f cluster-role-binding.yaml
执行成功后,来看看ServiceAccount的详细信息,执行如下命令
kubectl get sa -n nginx -oyaml
输出内容如下:
...
...
secrets:
- name: nginx-user-token-k9prg
可以看到,kubernetes会自动为一个ServiceAccount创建并分配一个Secret对象,这个Secret就是 这个ServiceAccount对应的用来与apiserver进行交互的授权文件,我们叫Token.Token 文件的内容一般是证书或者密码,它以一个 Secret 对象的方式保存在 Etcd 当中。
pod中指定ServiceAccount
apiVersion: apps/v1
kind: Deployment
...
spec:
template:
spec:
serviceAccountName: nginx-user
pod运行起来后,Secret对象被Kubernetes自动挂载到了容器的/var/run/secrets/kubernetes.io/serviceaccount 目录下.
我们老检验一下,执行如下命令进入pod查看
kubectl exec -it -n nginx nginx-7b8c5978fb-dcrj9 -- /bin/bash
然后执行如下命令:
ls /var/run/secrets/kubernetes.io/serviceaccoun
不出意外的话可以看到三个文件:
ca.crt namespace token
当然也可以执行如下命令,查看挂载信息:
kubectl describe po -n nginx nginx-7b8c5978fb-dcrj9
你应该可以找到如下内容:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from nginx-user-token-k9prg (ro)
最后
这篇文章主要讲解了RBAC的使用,需要注意的是,如果一个Pod没有声明serviceAccountName, Kubernetes 会自动在它的 Namespace 下创建一个名叫default的默认ServiceAccount, 然后分配给这个 Pod。 但在这种情况下,这个默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。