讲解了很多的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

发表评论

邮箱地址不会被公开。 必填项已用*标注