Kubernetes集群安全机制说明
Kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其中一个重要的任务,API Server是集群内部各个组件通信的中介,也是外部控制的入口。所以Kubernetes的安全机制基本就是围绕保护API Server来设计的。Kubernetes使用了认证(Authentication)、鉴权(Authorization)、准入控制(Admission Control)三步来保证API Server的安全。
认证(Authentication)
-
HTTP Token认证:通过一个Token来识别合法用户
- HTTP Token的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串-Token来表达客户端的方式,Token是一个很长的很复杂的字符串,每一个Token对应一个用户名存储在API Server能访问的文件中,当客户端发起API请求调用时,需要在HTTP Header里放入Token。
-
HTTP Base认证:通过用户名+密码的方式认证
用户名:密码
用BASE64算法进行编码后的字符串放在HTTP Request中的Header Authorization域里发送给服务端,服务端收到后进行解码,获取用户名和密码。 - HTTPS 证书认证:基于CA证书签名的数字证书认证
HTTPS 证书认证
需要认证的节点
两种类型
- Kubernetes组件对API Server的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy
- Kubernetes管理的Pod对容器的访问:Pod(dashborad也是以Pod形式运行)
安全性说明
- Controller Manager、Scheduler与API Server在同一台机器,所以直接使用API Server的非安全端口访问
--insecure-bind-address=127.0.0.1
- kubectl、kubelet、kube-proxy访问API Server都需要证书进行HTTPS双向认证
证书颁发
- 手动签发:通过K8s集群跟ca进行签发HTTPS证书
- 自动签发:kubelet首次访问API Server时,使用token做认证,通过后Controller Manager会为kubelet生成一个证书以后的访问都是用证书做认证了。
kubeconfig
kubeconfig文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥)、集群Context信息(集群名称、用户名)。Kubernetes组件通过启动时指定不同的kubeconfig文件可以切换到不同的集群。
ServiceAccount
Pod中的容器访问API Server,因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了,Kubernetes使用了Service Account解决Pod访问API Server的认证问题。
Secret和CA的关系
Kubernetes设计了一种资源叫做Secret,分为两类,一种是用于ServiceAccount的service-account-token,另一种是用于保存用户自定义保密信息的Oqaque,ServiceAccount中用到包含三个部分:Token、ca.crt、namespace
- Token:是使用了API Server私钥签名的JWT,用于访问API Server时,Server端认证
- ca.crt:根证书,用于Client端验证API Server发送的证书
-
namespace:标识这个service-account-token的作用域名空间
默认情况下,每个namespace都会有一个ServiceAccount,如果Pod在创建时没有指定ServiceAccount,就会使用Pod所属的namespace的ServiceAccount。
鉴权(Authorization)
上面的认证过程,只是确认通信的双方都确认对方是可信的,进而可以互相通信。
鉴权是确定请求方有哪些资源权限,API Server 内部通过用户认证后,然后进入授权流程。对合法用户进行授权并且随后在用户访问时进行鉴权,是权限管理的重要环节。API Server目前支持以下几种授权策略(通过API Server的启动参数--authorization-mode
设置)
- Always Deny: 表示拒绝所有的请求,一般用于测试。
- Always Allow:允许接收所有请求,如果集群不需要授权流程,则可以采用该策略。
- ABAC: 基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制。
- Webhook:通过调用外部REST服务对用户进行授权。
- RBAC:Role-Base Access Control, 基于角色的访问控制。
RBAC授权模式
RBAC(Role-Based Access Control,基于角色的访问控制)在Kubernetes v1.5引入,在v1.6版本时升级为Beta版本,并成为kubeadm安装方式下的默认选项,组建其重要程度。相对于其他的访问控制方式,RBAC具有如下优势。
- 对集群中的资源和非资源权限均有完整的覆盖。
- 整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作。
- 可以在运行时进行调整,无须重新启动API Server。
要使用RBAC授权模式,则需要在API Server的启动参数中加上--authorization-mode=RBAC
。
角色
- Role:授权特定命名空间的访问权限
- ClusterRole:授权所有命名空间的访问权限
角色绑定
- RoleBinding:将角色绑定到主体(即subject)
- ClusterRoleBinding:将集群角色绑定到主体
主体(subject)
- User:用户
- Group:用户组
- ServiceAccount:服务账号
1、RBAC的API资源对象说明
BAC引入了4个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding。同其他API资源对象一样,用户可以使用kubectl或者API调用方式操作这些资源对象。
需要注意的是Kubernetes并不会提供用户管理,那么User、Group、ServiceAccount指定的用户又是从哪里来的呢?Kubernetes组件(kubectl、kube-proxy)或是其他自定义的用户在向CA申请证书时,需要提供一个证书请求文件。
[root@k8s-master1 ~]# vim jane-csr.json
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
- API Server会把客户端证书的
CN
字段作为User,把names.O
字段作为Group - kubelet使用TLS Bootstaping认证时,API Server可以使用 Bootstrap Tokens或者Token authentication file验证=token,无论哪一种,Kubernetes都会为token绑定一个默认的User和Group
- Pod使用ServiceAccount认证时,service-account-token中的JWT会保存User信息
- 有了用户信息,在创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了。
Role and ClusterRole
在RBAC API中Role表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过RBAC对其进行减少的操作;Role可以定义在一个namespace中,如果想要跨namespace则可以创建ClusterRole
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # ""空字符串,表示核心API群
resources: ["pods"]
verbs: ["get", "watch", "list"]
rules中的参数说明:
- apiGroups: 支持的API组列表,例如“apiVersion: batch/v1”、“apiVersion: extensions:v1beta1”、“apiVersion: apps/v1beta1”等。
- resources:支持的资源对象列表,例如pods、deployments、jobs等。
- verbs:对资源对象的操作方法列表,例如get、watch、list、delete、replace、patch等。
ClusterRole
ClusterRole处理具有和Role一致的命名空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权。
- 集群级别的资源控制,例如Node(节点)。
- 非资源类型的路径,例如“/healthz”。
- 包含全部命名空间的资源,例如pods(用于kubectl get pods --all-namespaces这样的操作授权)。
下面的ClusterRole可以让用户有权访问任意一个或所有命名空间的secrets(视其绑定方式而定):
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# ClusterRole不受限于命名空间,所以省略了namespace name的定义
name: secret-reader
rules:
- apiGroups: [""] # ""空字符串,表示核心API群
resources: ["secrets"]
verbs: ["get", "watch", "list"]
角色绑定(RoleBinding)和集群角色绑定(ClusterRoleBinding)
RoleBinding可以将角色中定义的权限授予用户或用户组,RoleBinding包含一组权限列表(subjects),权限列表中包含有不同形式的待授予权限资源类型(users、groups、Service Account);RoleBinding同样包含对被Bind的Role引用,RoleBinding适用于某个命名空间内授权,ClusterRoleBinding适用于集群范围内授权。
下面例子中的RoleBinding将在default命名空间中把pod-reader角色授予用户jane,这一操作让jane可以读取default命名空间中的Pod:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: read-pods
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
RoleBinding也可以引用ClusterRole,来对当前namespace内用户、用户组或ServiceAccount进行授权,这种操作允许集群管理员在整个集群内定义一些通用ClusterRole,然后在不同的namespace中使用RoleBinding来引用
例如,以下RoleBinding引用一个ClusterRole,这个ClusterRole具有整个集群内对secrets的访问权限,但是其授权用户dave只能访问development空间中的secrets(因为RoleBinding定义在development命名空间)
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: development
name: read-secret
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
集群角色绑定中的角色只能是集群角色,用于进行集群级别或者对所有命名空间都生效的授权。下面的例子允许manager组的用户读取任意namespace中的secret:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: development
name: read-secrets-global
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
资源(resources)与主体(subjects)
资源(resources)介绍
- 在Kubernets中,主要的资源包括:Pods、Nodes、Services、Deployment、Replicasets、Statefulsets、Namespace、Persistents、Secrets和ConfigMaps等。
- 同时,有些资源下面存在子资源,例如:Pod下就存在log子资源。
# logs资源就属于pods的子资源,API中URL样例如下
Get /api/v1/namespaces/{namespace}/pods/{name}/log
示例1:普通角色的资源列表:
[root@k8smaster01 study]# vi pod-and-pod_log.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods","pods/log"]
verbs: ["get","list"]
解释:如上限定在default的命名空间的名为pod-and-pod-logs-reader的普通角色,对pod和pods/log资资源就有get和list的权限。
示例2:更精细粒度的资源控制,可通过resourceNamess指定特定的资源实例,以限制角色只能够对具体的某个实例进行访问控制。
[root@k8smaster01 study]# vi updater_configmap.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["my-configmap"]
verbs: ["update","get"]
解释:如上限定在default的命名空间的名为configmap-updater的普通角色,对名为my-configmap的configmaps类型的特定资源,具有update和get权限。
主体(subjects)介绍
- RBAC授权中的主体可以是组,用户或者服务帐户。用户通过字符串表示,比如“alice”、“bob@example.com”等,具体的形式取决于管理员在认证模块中所配置的用户名。
- system: 被保留作为用来Kubernetes系统内部使用,因此不能作为用户的前缀。组也有认证模块提供,格式与用户类似。
示例1:类型为user(用户)。
subjects:
- kind: User
name: "alice@example.com"
apiGroup: rbac.authorization.k8s.io
示例2:类型为group(组)。
subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
示例3:查看default的服务账户。
subjects:
- kind: ServiceAccount
name: default
namespace: kube-system
准入控制
Kubernetes系统通过三个独⽴的组件间的相互协作来实现服务账户的⾃动化,三个组件具体为:Admission Controllers准⼊控制器、令牌控制器(token controller)和Service Account账户控制器。Service Account控制器负责为名称空间管理相应的资源,并确保每个名称空间中都存在⼀个名为“default”的Service Account对象。
当请求通过了前面的认证和授权之后,还需要经过准入控制处理通过之后,apiserver 才会处理这个请求。Admission Control 有一个准入控制列表,我们可以通过命令行设置选择执行哪几个准入控制器。只有所有的准入控制器都检查通过之后,apiserver 才执行该请求,否则返回拒绝。
为什么需要Admission Control
在kubernetes中,一些高级特性正常运行的前提条件为,将一些准入模块处于enable状态。总结下,对于kubernetes apiserver,如果不适当的配置准入控制模块,他就不能称作是一个完整的server,某些功能也不会正常的生效。
主要的准入控制器介绍
AlwaysAdmit
允许所有请求
AlwaysDeny
拒绝所有请求
AlwaysPullImages
强制设置Pod拉取镜像策略为Always。这样能够保证私有镜像只能被有拉取权限的使用者使用。
DenyExecOnPrivileged
它会拦截所有想在privileged container上执行命令的请求。(如果自己的集群支持privileged container,自己又希望限制用户在这些privileged container上执行命令,那么强烈推荐使用它。)
DenyEscalatingExec
这个插件禁止那些通过主机执行而获得privileges去执行exec和attach Pod的命令。
ImagePolicyWebhook
通过webhook决定image策略,需要同时配置–admission-control-config-file
ServiceAccount
一个serviceAccount为运行在pod内的进程添加了相应的认证信息。当准入模块中开启了此插件(默认开启),如果pod没有serviceAccount属性,将这个pod的serviceAccount属性设为“default”;确保pod使用的serviceAccount始终存在;如果LimitSecretReferences 设置为true,当这个pod引用了Secret对象却没引用ServiceAccount对象,弃置这个pod;如果这个pod没有包含任何ImagePullSecrets,则serviceAccount的ImagePullSecrets被添加给这个pod;如果MountServiceAccountToken为true,则将pod中的container添加一个VolumeMount 。
ResourceQuota
它会观察所有的请求,确保在namespace中ResourceQuota对象处列举的container没有任何异常。如果在kubernetes中使用了ResourceQuota对象,就必须使用这个插件来约束container。(推荐在admission control参数列表中,这个插件排最后一个。)
LimitRanger
实现配额控制。他会观察所有的请求,确保没有违反已经定义好的约束条件,这些条件定义在namespace中LimitRange对象中。如果在kubernetes中使用LimitRange对象,则必须使用这个插件。
SecurityContextDeny
禁止创建设置了 Security Context 的 pod。这个插件将会将使用了 SecurityContext的pod中定义的选项全部失效。关于 SecurityContext的描述:SecurityContext 在container中定义了操作系统级别的安全设定(uid, gid, capabilities, SELinux等等)。
NamespaceLifecycle
确保处于termination状态的namespace不再接收新的对象创建请求,并拒绝请求不存在的namespace。
InitialResources
根据镜像的历史使用记录,为容器设置默认资源请求和限制
DefaultStorageClass
为PVC设置默认StorageClass
DefaultTolerationSeconds
设置Pod的默认forgiveness toleration为5分钟
PodSecurityPolicy
使用Pod Security Policies时必须开启
NodeRestriction
限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源(v1.7版本以上才支持)
推荐的设置控制器顺序:
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
参考:
https://www.cnblogs.com/xzkzzz/p/9909468.html
https://www.cnblogs.com/Dev0ps/p/10852445.html
https://www.kubernetes.org.cn/1995.html
https://www.kubernetes.org.cn/4061.html
//www.greatytc.com/p/5a6e9ee8ab5a
//www.greatytc.com/p/fd61330596eb