Kubernetes常用资源对象-RBAC

前⾯我们学习了 Kubernetes 中的两个用于配置信息的重要资源对象: ConfigMap 和 Secret,其实到这里我们基本上学习的内容已经覆盖到 Kubernetes 中⼀些重要的资源对象了,来部署⼀个应⽤程序是完全没有问题的了。在我们演示⼀个完整的示例之前,还需要讲解⼀个重要的概念: RBAC – 基于角色的访问控制。

RBAC 使用 rbac.authorization.k8s.io API Group 来实现授权决策,允许管理员通过 KubernetesAPI 动态配置策略,要启用 RBAC ,需要在 apiserver 中添加参数 –authorization-mode=RBAC ,如果使用的 kubeadm 安装的集群,1.6 版本以上的都默认开启了 RBAC ,可以通过查看 Master 节点上apiserver 的静态 Pod 定义文件:

img

如果是⼆进制的方式搭建集群,添加这个参数过后,记得要重启 apiserver 服务。

1、RBAC API对象

Kubernetes 有⼀个很基本的特性就是它的所有资源对象都是模型化的 API 对象,允许执行CRUD(Create、Read、Update、Delete)操作(也就是我们常说的增、删、改、查操作),比如下⾯的这下资源:

  • Pods
  • ConfigMaps
  • Deployments
  • Nodes
  • Secrets
  • Namespaces

上⾯这些资源对象的可能存在的操作有:

  • create
  • get
  • delete
  • list
  • update
  • edit
  • watch
  • exec

在更上层,这些资源和 API Group 进行关联,比如 Pods 属于 Core API Group,而 Deployements 属于 apps API Group,要在 Kubernetes 中进行 RBAC 的管理,除了上⾯的这些资源和操作以外,我们还需要另外的⼀些对象:

1、Rule:规则,规则是⼀组属于不同 API Group 资源上的⼀组操作的集合;

2、Role 和 ClusterRole:角色和集群角色,这两个对象都包含上⾯的 Rules 元素,⼆者的区别在于,在 Role 中,定义的规则只适⽤于单个命名空间,也就是和 namespace 关联的,而ClusterRole 是集群范围内的,因此定义的规则不受命名空间的约束。另外 Role 和 ClusterRole在 Kubernetes 中都被定义为集群内部的 API 资源,和我们前⾯学习过的 Pod、ConfigMap 这些类似,都是我们集群的资源对象,所以同样的可以使⽤我们前⾯的 kubectl 相关的命令来进⾏操作;

3、Subject:主题,对应在集群中尝试操作的对象,集群中定义了3种类型的主题资源:

  • User Account:用户,这是有外部独立服务进行管理的,管理员进行私钥的分配,用户可以使用 KeyStone或者 Goolge 帐号,甚至⼀个用户名和密码的文件列表也可以。对于用户的管理集群内部没有⼀个关联的资源对象,所以用户不能通过集群内部的 API 来进行管理
  • Group:组,这是用来关联多个账户的,集群中有⼀些默认创建的组,比如cluster-admin;
  • Service Account:服务帐号,通过 Kubernetes API 来管理的⼀些⽤户帐号,和 namespace进行关联的,适用于集群内部运⾏的应用程序,需要通过 API 来完成权限认证,所以在集群内部进⾏权限操作,我们都需要使用到 ServiceAccount,这也是我们这节课的重点。

4、RoleBinding 和 ClusterRoleBinding:角色绑定和集群角色绑定,简单来说就是把声明的 Subject 和我们的 Role 进行绑定的过程(给某个用户绑定上操作的权限),⼆者的区别也是作用范围的区别:RoleBinding 只会影响到当前 namespace 下⾯的资源操作权限,而 ClusterRoleBinding 会影响到所有的 namespace。

接下来我们来通过几个示例来演示下 RBAC 的配置方法。

2、创建访问某个namespace的用户

我们来创建⼀个 User Account,只能访问 kube-system 这个命名空间:

  • username: zoukun
  • group: shdz

第1步:创建用户凭证

我们前面已经提到过, Kubernetes 没有 User Account 的 API 对象,不过要创建⼀个用户帐号的话也是挺简单的,利用管理员分配给你的⼀个私钥就可以创建了,这个我们可以参考官方文档中的方法,这里我们来使用 OpenSSL 证书来创建⼀个 User,当然我们也可以使用更简单的 cfssl 工具来创建:

我们给用户zoukun创建一个私钥、命名为:zoukun.key

openssl genrsa -out zoukun.key 2048

img

使用刚刚创建的私钥创建⼀个证书签名请求文件:zoukun.csr,要注意需要确保在 -subj 参数中指定用户名和组(CN表示用户名,O表示组):

openssl req -new -key zoukun.key -out zoukun.csr -subj "/CN=zoukun/O=shdz"

img

然后找到 Kubernetes 集群的 CA ,因为我们使用的是 kubeadm 安装的集群, CA 相关证书位于 /etc/kubernetes/pki/ 目录下面,如果你是⼆进制方式搭建的,你应该在最开始搭建集群的时候就已经指定好了 CA 的⽬录,我们会利用该目录下面的 ca.crt 和 ca.key 两个文件来批准上⾯的证书请求。
生成最终的证书文件,我们这里设置证书的有效期为500天,然后查看当前文件夹下⾯是否生成了⼀个证书文件::

openssl x509 -req -in zoukun.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out zoukun.crt -days 500

img

现在我们可以使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context):

kubectl config set-credentials zoukun  --client-certificate=zoukun.crt  --client-key=zoukun.key

img

我们可以看到⼀个用户 zoukun 已经创建了,然后为这个用户设置新的 Context:

kubectl config set-context zoukun-context --cluster=kubernetes --namespace=kube-system --user=zoukun

img

用户 zoukun 就已经创建成功了,现在我们使用当前的这个配置文件来操作 kubectl 命令的时候,应该会出现错误,因为我们还没有为该用户定义任何操作的权限:

kubectl get pods --context=zoukun-context

img

第2步:创建角色

用户创建完成后,接下来就需要给该用户添加操作权限,我们来定义⼀个 YAML 文件,创建⼀个允许用户操作 Deployment、Pod、ReplicaSets 的角色,如下定义:(zoukun-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: zoukun-role
  namespace: kube-system
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']

注: Pod 属于 core 这个 API Group,在 YAML 中用空字符就可以,而 Deployment 属于 apps 这个API Group, ReplicaSets 属于 extensions 这个 API Group(我怎么知道的?当然还是去官方文档查看),所以rules 下面的 apiGroups 就综合了这几个资源的 API Group:[“”, “extensions”, “apps”],其中 verbs 就是我们上⾯提到的可以对这些资源对象执⾏的操作,我们这里需要所有的操作方法,所以我们也可以使⽤[‘*’]来代替。创建Role:

kubectl create -f zoukun-role.yaml

img

注:这里我们没有使用上⾯的 zoukun-context 这个上下文了,因为已经没有权限了。

第3步:创建角色权限绑定

Role 创建完成了,我们现在要把上面创建的 Role 和用户 zoukun 进行绑定,这里需要创建⼀个 RoleBinding 对象,在 kube-system 这个命名空间下⾯将上⾯的 zoukun-role 角色和用户 zoukun 进行绑定:(zoukun-rolebinding.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: zoukun-rolebinding
  namespace: kube-system
subjects:
- kind: User
  name: zoukun
  apiGroup: ""  # core可以为空
roleRef:
  kind: Role
  name: zoukun-role
  apiGroup: ""

注:上面的 YAML ⽂件中我们看到了 subjects 关键字,这里就是我们上⾯提到的用来尝试操作集群的对象,这里对应上⾯的 User 帐号 zoukun,使用 kubectl 创建上⾯的资源对象:

kubectl create -f zoukun-rolebinding.yaml

img

第4步:权限测试

现在我们就可以用上⾯的 zoukun-context 上下文来操作集群了:

img

我们可以看到使用 kubectl 并没有指定 namespace ,这是因为我们已经为该用户分配了权限了,如果我们在后⾯加上⼀个 -n default 呢:

img

发现无法访问、因为该用户并没有 default 这个命名空间的操作权限。

3、创建只能访问某个namespace的ServerAccount

上⾯我们创建了⼀个只能访问某个命名空间的普通用户,我们前面也提到过 subjects 下面还有⼀个类型的主题资源:ServiceAccount,现在我们来创建⼀个集群内部用户,这个用户只能操作 kube-system 命名空间下面的 pods 和 deployments,首先来创建⼀个 ServiceAccount 对象:

kubectl create sa zoukun-sa -n kube-system

img

当然我们也可以定义成 YAML 文件的形式来创建,然后新建⼀个 Role 对象:(zoukun-sa-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: zoukun-sa-role
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

可以看到我们这里定义的角色没有创建、删除、更新 Pod 的权限,待会我们可以重点测试⼀下,创建该 Role 对象:

kubectl create -f zoukun-sa-role.yaml

img

然后创建⼀个 RoleBinding 对象,将上面的 zoukun-sa 和角色 zoukun-sa-role 进行绑定:(zoukun-sa-rolebinding.yaml)

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: zoukun-sa-rolebinding
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: zoukun-sa
  namespace: kube-system
roleRef:
  kind: Role
  name: zoukun-sa-role
  apiGroup: rbac.authorization.k8s.io

添加这个资源对象:

kubectl create -f zoukun-sa-rolebinding.yaml

img

但是我们怎么去验证这个 ServiceAccount 呢?我们前⾯的章节中提到过 ServiceAccount 会生成⼀个 Secret 对象和它进行映射,这个 Secret 里面包含⼀个 token,我们可以利用这个 token 去登录 Dashboard,然后我们就可以在 Dashboard 中来验证功能是否符合预期了:

kubectl get secret -n kube-system |grep zoukun-sa
zoukun-sa-token-7l4wj       kubernetes.io/service-account-token   3      9m30s
# 会⽣成⼀串很⻓的base64后的字符串
kubectl get secret zoukun-sa-token-7l4wj -o jsonpath={.data.token} -n kube-system |base64 -d

使用下面的 token 去 Dashboard 页面进行登录:

img

img

我们可以看到上面的错误提示信息,这是因为我们登录进来后默认跳转到 default 命名空间,我们切换到 kube-system 命名空间下⾯就可以了:

img

我们可以看到现在可以访问pod列表了,但是也会有⼀些其他额外的提示:events is forbidden: User “system:serviceaccount:kube-system:zoukun-sa” cannot list resource “events” in API group “” in the namespace “kube-system”这是因为当前登录用户只被授权访问 pod 和 deployment 的权限。同样的,访问下deployment也是可以看到的。

我们可以根据自己的需求来对访问用户的权限进行限制,可以自己通过 Role 定义更加细粒度的权限,也可以使用系统内置的⼀些权限。

4、创建可以访问所有namespace的ServerAccount

刚刚我们创建的 zoukun-sa 这个 ServiceAccount 和⼀个 Role 角色进行了绑定,如果我们现在创建⼀个新的 ServiceAccount,需要他操作的权限作用于所有的 namespace,这个时候我们就需要使用到ClusterRole 和 ClusterRoleBinding 这两种资源对象了。同样,⾸先新建⼀个 ServiceAcount 对象:(zoukun-sa2.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: zoukun-sa2
  namespace: kube-system

创建:

kubectl create -f zoukun-sa2.yaml

img

然后创建⼀个 ClusterRoleBinding 对象(zoukun-clusterolebinding.yaml):

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: zoukun-sa2-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: zoukun-sa2
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

从上⾯我们可以看到我们没有为这个资源对象声明 namespace,因为这是⼀个 ClusterRoleBinding 资源对象,是作用于整个集群的,我们也没有单独新建⼀个 ClusterRole 对象,而是使用的 clusteradmin这个对象,这是 Kubernetes 集群内置的 ClusterRole 对象,我们可以使用 kubectl get clusterrole 和 kubectl get clusterrolebinding 查看系统内置的⼀些集群角色和集群角色绑定,这里我们使用的 cluster-admin 这个集群角色是拥有最高权限的集群角色,所以⼀般需要谨慎使用该集群角色。

img

创建上⾯集群角色绑定资源对象,创建完成后同样使⽤ ServiceAccount 对应的 token 去登录Dashboard 验证一下:

kubectl create -f zoukun-clusterolebinding.yaml
kubectl get secret -n kube-system |grep zoukun-sa2
zoukun-sa2-token-2qdqz      kubernetes.io/service-account-token   3      101s
# 会⽣成⼀串很⻓的base64后的字符串
kubectl get secret zoukun-sa2-token-2qdqz -o jsonpath={.data.token} -n kube-system |base64 -d

img

img

在最开始接触到 RBAC 认证的时候,我们可能不太熟悉,特别是不知道应该怎么去编写 rules规则,大家可以去分析系统自带的 clusterrole、clusterrolebinding 这些资源对象的编写方法我们可以利用 kubectl 的 get、describe、 -o yaml 这些操作来分析,所以 kubectl 最基本的用户⼀定要掌握好。RBAC 只是 Kubernetes 中安全认证的⼀种方法,当然也是现在最重要的⼀种方式,后⾯我们再和大家⼀起聊⼀聊 Kubernetes 中安全设计。

推荐文章