k8s series 13: 认证,授权

737 阅读9分钟

  这是我参与更文挑战的第10天,活动详情查看: 更文挑战   

  k8s集群中不管所有组件 对集群的增删改查,都是通过api server这个组件进行的,当然后期使用api操作集群也是通过api server这个组件。因为api server可以操作etcd,而其他组件都不可以。

那么api server的安全性就非常关键了,集群对api 做了准入控制机制,其中有认证管理,和授权管理

认证管理

认证方式

  • https证书双向认证: 基于CA根证书分出来的组件证书进行 双向认证
  • http token: 基于一个token来识别合法用户
  • http base:  简单的http用户名密码认证

用户类型

  • 常规用户:  使用kubectl 操作集群的用户
  • 服务用户: 创建账户方便pod运行时获取集群权限的用户

下图可以看出 我们使用常规用户 admin用户 使用的私钥证书是apiserver组件的 进行认证

服务账号,创建

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard

查看服务账号的token,以dashboard为例,使用输出结果中的toekn可以登陆到面版

#查看token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

http base认证是将用户名密码使用base64加密后放到header 里面发送给服务端进行认证,很多工具都支持

查看集群中的用户

kubectl get user

查看集群中的角色

kubectl get clusterrole

授权管理

授权方式

  • rbac授权:
  • abac授权:
  • node授权
  • webhook授权

 在k8s授权机制有很多,上述就是,比较常用的是rbac,rbac授权模型在管理后台中非常常见

rabc(role based access control)是基于角色做访问控制

abac(attribute based access control)基于属于做访问控制

node 专用对节点 kubelet发送请求给api server做的授权

webhook是基于web实用的http回调授权,方便访问集群之后的服务

默认配置中启用了node和rbac鉴权器,在配置中可查看

cat /etc/kubernetes/manifests/kube-apiserver.yaml

node

鉴权器允许 kubelet 执行 API 操作,默认启用

读取操作:

  • services
  • endpoints
  • nodes
  • pods
  • secrets、configmaps、pvcs 以及绑定到 kubelet 节点的与 pod 相关的持久卷

写入操作:

  • 节点和节点状态(启用 NodeRestriction 准入插件以限制 kubelet 只能修改自己的节点)
  • Pod 和 Pod 状态 (启用 NodeRestriction 准入插件以限制 kubelet 只能修改绑定到自身的 Pod)
  • 事件

鉴权相关操作:

  • 对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限
  • 为委派的身份验证/授权检查创建 tokenreviews 和 subjectaccessreviews 的能力

webhook

某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知

ABAC授权

abac 定义了访问控制范例,其中通过使用将属性组合在一起的策略来向用户授予访问权限

因实际生产中使用不多,这里不多做介绍,详情见官网: kubernetes.io/zh/docs/ref…

重点介绍RBAC

RBAC授权

  基于角色的授权模型在环境中使用 非常多,像上一章的存储 创建nfs sc的时候就使用到了

而且rbac 鉴权默认是启用的,它的机制来源于rbac.authorization.k8s.io API对象

API对象

  RBAC API 声明了四种kubernetes对象: Role、ClusterRole、Rolebinding、ClusterRoleBinding

可以使用kubectl工具操作这些对象

Role 和 ClusterRole

RBAC 的Role或ClusterRole中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)。

Role 必须对应一个namespace

ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的, 不可两者兼具。

ClusterRole 有若干用法。你可以用它来:

  1. 定义对某namespace域对象的访问权限,并将在各个namespace内完成授权;
  2. 为namespace作用域的对象设置访问权限,并跨所有namespace执行授权;
  3. 为集群作用域的资源定义访问权限。

在名字空间内定义角色,应该使用 Role; 在定义集群范围的角色,应该使用 ClusterRole

Role example

具有default namespace中 pod对象的 读访问权限

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

ClusterRole example

具有任意一个namespace的 Secret对象 读访问权限,或者跨namespace的访问权限(取决于该角色是如何绑定的)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
  name: secret-reader
rules:
- apiGroups: [""]
  # 在 HTTP 层面,用来访问 Secret 对象的资源的名称为 "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

RoleBinding 和 ClusterRoleBinding

角色绑定是将 角色定义的权限赋予一个或者一组用户

RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权

一个 RoleBinding 可以引用同一namespace中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的namespace。 如果你希望将 ClusterRole 绑定到集群中所有namespace,你要使用 ClusterRoleBinding

RoleBinding example

 将 pod-reader 中的 Role 授予在 default  namespace中的用户 "jane"。 这样,用户 "jane" 就具有了读取 "default" namespace中 pods 的权限

apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pods
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
  name: jane # "name" 是不区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
  kind: Role # 此字段必须是 Role 或 ClusterRole
  name: pod-reader     # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
  apiGroup: rbac.authorization.k8s.io

RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在namespace的资源。这种引用使得你可以跨整个集群定义一组通用的角色, 之后在多个名字namespace中复用

例如下面的 RoleBinding 引用的是一个 ClusterRole,"dave"(这里的主体, 不区分大小写)只能访问 "development" 名字空间中的 Secrets 对象,因为 RoleBinding 所在的名字空间(由其 metadata 决定)是 "development"

apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "dave" 能够读取 "default" 名字空间中的 Secrets
# 你需要一个名为 "secret-reader" 的 ClusterRole
kind: RoleBinding
metadata:
  name: read-secrets
  # RoleBinding 的名字空间决定了访问权限的授予范围。
  # 这里仅授权在 "development" 名字空间内的访问权限。
  namespace: development
subjects:
- kind: User
  name: dave # 'name' 是不区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding example

要跨整个集群完成访问权限的授予,可以使用一个 ClusterRoleBinding。 下面的 ClusterRoleBinding 允许 "manager" 组内的所有用户访问任何namespace中的 Secrets

apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 secrets
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # 'name' 是不区分大小写的
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

创建了绑定之后,不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef 将导致合法性检查错误。 如果想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。

这种限制有两个主要原因:

  1. 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改 roleRef, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许修改 roleRef 的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。
  2. roleRef 设置为不可以改变,这使得可以为用户授予对现有绑定对象的 update 权限, 这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色。

命令 kubectl auth reconcile 可以创建或者更新包含 RBAC 对象的清单文件, 并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色

*注 文中很多内容来源于官方文档

引用地址: kubernetes.io/zh/docs/ref…

准入控制

通过了前面的认证和授权之后,还需要经过准入控制处理通过之后,apiserver 才会处理这个请求。Admission Control 有一个准入控制列表,我们可以通过命令行设置选择执行哪几个准入控制器。只有所有的准入控制器都检查通过之后,apiserver 才执行该请求,否则返回拒绝。

因为准入控制器众多,这里把常见几个简单介绍一下:

  • AlwaysAdmit:允许所有请求
  • AlwaysDeny:拒绝所有请求
  • AlwaysPullImages:在启动容器之前总是去下载镜像
  • ServiceAccount:将 secret 信息挂载到 pod 中,比如 service account token,registry key 等
  • ResourceQuota 和 LimitRanger:实现配额控制
  • SecurityContextDeny:禁止创建设置了 Security Context 的 pod

查看默认启用的:

kube-apiserver -h | grep enable-admission-plugins

如果你是用kubeadm安装的集群,需要登陆到api server容器上执行上面的命令

所有准入控制器的清单:  kubernetes.io/docs/refere…

实战例子

以nfs sc为例

创建namespace

apiVersion: v1
kind: Namespace
metadata:
  name: dmp-storage-class

创建服务账号

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: dmp-storage-class

创建集群角色

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]

绑定集群角色

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: dmp-storage-class
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

创建角色

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: dmp-storage-class
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

绑定角色

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: dmp-storage-class
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: dmp-storage-class
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

使用

在deployment控制器中spec.spec 定义

serviceAccountName: nfs-client-provisioner

流程如下

  1. 创建一个namespace dmp-storage-class

  2. 在namespace中创建一个ServiceAccount nfs-client-provisioner

  3. 创建pv,pvc,sc,event等增删改查权限的集群角色

  4. 将集群角色绑定到服务账号 nfs-client-provisioner

  5. 创建endpoints的增删改查权限的角色

  6. 将角色 绑定到服务账号 nfs-client-provisioner

  7. 在对象控制器引入serviceAccountName 既可让该 对象 拥有以上权限

安全工具

虽然api server在认证,授权方面有很多的选项,但是有一些安全辅助工具很不错

kube-bench

kube-bench 是通过运行 CIS Kubernetes Benchmark 中记录的检查来检查 Kubernetes 是否安全部署的工具

 github.com/aquasecurit…

Popeye

Popeye 是一个实用程序,可扫描实时 Kubernetes 集群并报告已部署资源和配置的潜在问题

github.com/derailed/po…