这是我参与更文挑战的第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 有若干用法。你可以用它来:
- 定义对某namespace域对象的访问权限,并将在各个namespace内完成授权;
- 为namespace作用域的对象设置访问权限,并跨所有namespace执行授权;
- 为集群作用域的资源定义访问权限。
在名字空间内定义角色,应该使用 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
字段的内容,必须删除重新创建绑定对象。
这种限制有两个主要原因:
- 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改
roleRef
, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许修改roleRef
的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。 - 将
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
流程如下
-
创建一个namespace dmp-storage-class
-
在namespace中创建一个ServiceAccount nfs-client-provisioner
-
创建pv,pvc,sc,event等增删改查权限的集群角色
-
将集群角色绑定到服务账号 nfs-client-provisioner
-
创建endpoints的增删改查权限的角色
-
将角色 绑定到服务账号 nfs-client-provisioner
-
在对象控制器引入serviceAccountName 既可让该 对象 拥有以上权限
安全工具
虽然api server在认证,授权方面有很多的选项,但是有一些安全辅助工具很不错
kube-bench
kube-bench 是通过运行 CIS Kubernetes Benchmark 中记录的检查来检查 Kubernetes 是否安全部署的工具
Popeye
Popeye 是一个实用程序,可扫描实时 Kubernetes 集群并报告已部署资源和配置的潜在问题