Kubernetes过一系列机制来实现集群的安全机制,包括API Server的认证受权、准入控制机制及保护敏感信息的Secret机制等。集群的安全性必须考虑如下的几个目标:redis
下面分别从Authentication、Authorization、Admission Control、Secret和Service Account等方面来讲明集群的安全机制。算法
Kubernetes集群中全部资源的访问和变动都是经过Kubernetes API Server的REST API来实现的,因此集群安全的关键点在于识别认证客户端身份(Authentication)以及访问权限的受权(Authorization)。docker
Kubernetes提供管理三种级别的客户端身份认证方式:数据库
SSL双向认证步骤:后端
CA认证流程图:api
上述是双向SSL协议的具体通讯过程,这种状况要求服务器和用户双方都有证书。单向认证SSL协议不须要客户拥有CA证书,对应上面的步骤,只需将服务器端验证客户端证书的过程去掉,以及在协商对称密码方案和对称通话秘钥时,服务器端发送给客户端的是没有加过密的(这并不影响SSL过程的安全性)密码方案。安全
HTTP Token原理:HTTP Token的认证是用一个很长的特殊编码方式的而且难以被模仿的字符串——Token来代表客户身份的一种方式。在一般状况下,Token是一个复杂的字符串,好比咱们用私钥签名一个字符串的数据就能够做为一个Token,此外每一个Token对应一个用户名,存储在API Server能访问的一个文件中。当客户端发起API调用请求时,须要在HTTP Header里放入Token,这样一来API Server就可以识别合法用户和非法用户了。服务器
HTTP Base:常见的客户端帐号登陆程序,这种认证方式是把“用户名+冒号+密码”用BASE64算法进行编码后的字符串放在HTTP REQUEST中的Header Authorization域里发送给服务端,服务端收到后进行解码,获取用户名及密码,而后进行用户身份的鉴权过程。并发
对合法用户进行受权(Authorization)而且随后在用户访问时进行鉴权,是权限与安全系统的重要一环。受权就是授予不一样用户不一样访问权限,API Server目前支持一下集中受权策略:框架
为了简化受权的复杂度,对于ABAC模式的受权策略,Kubernetes仅有下面四个基本属性:
当API Server启用ABAC模式时,须要指定受权文件的路径和名字(--authorization_policy_file=SOME_FILENAME),受权策略文件里的每一行都是一个Map类型的JOSN对象,被称为访问策略对象,咱们能够经过设置“访问策略对象”中的以下属性来肯定具体的受权行为:
eg:
经过认证和鉴权以后,客户端并不能获得API Server的真正响应,这个请求还需经过Admission Control所控制的一个“准入控制链”的层层考验,Admission Control配备有一个“准入控制器”的列表,发送给API Server的任何请求都须要经过列表中每一个准入控制器的检查,检查不经过API Server拒绝此调用请求。此外,准入控制器还可以修改请求参数以完成一些自动化的任务。好比Service Account这个控制器,当前可配置的准入控制以下:
在API Server上设置--admission-control参数,便可定制咱们须要的准入控制链,若是启用多种准入控制选项,则建议的设置以下:
下面着重介绍三个准入控制器:
Security Context时运用于容器的操做系统安全设置(uid、gid、capabilities、SELinux role等),Admission Control的SecurityContextDeny插件的做用是,禁止建立设置了Security Context的Pod,例如包含如下配置项的Pod:
ResourceQuota不只可以限制某个Namespace中建立资源的数量,并且可以限制某个namespace中被Pod所请求的资源总量。该准入控制器和资源对象ResourceQuota一块儿实现了资源的配额管理;
准入控制器LimitRanger的做用相似于上面的ResourceQuota控制器,这对Namespace资源的每一个个体的资源配额。该插件和资源对象LimitRange一块儿实现资源限制管理。
Servuce Account是一种帐号,但他并非给Kubernetes的集群的用户(系统管理员、运维人员、租户用户等),而是给运行在Pod里的进程用的,它为Pod里的进程提供必要的身份证实。
Pod中访问Kubernetes API Server服务的时候,是以Service方式访问服务名为kubernetes这个服务的,而kubernetes服务又只在HTTPS安全端口443上提供服务,那么如何进行身份认证呢?在Kubernetes的官方文档并无清除的说明这个问题。
经过查看源码获知这是在用一种相似HTTP Token的新的认证方式--ServiceAccount Auht,Pod中的客户端调用Kubernetes API的时候,在HTTP Header中传递了一个Token字符串,这相似于以前提到的HTTP Token认证方式,存在如下几个不一样点:
明白原理以后。接下来分析认证过程当中涉及的Pod中的三个文件:
这三个文件因为参与到Pod进程与API Server认证的过程当中,起到了相似Secret(私密凭据)的做用,因此他们被称为Kubernetes Secret对象。Secret从属于ServiceAccount资源对象,属于Service Account的一部分,一个ServiceAccount对象里面能够包括多个不一样的Secret对象,分别用于不一样目的的认证活动。
下面经过命令来直观的加深对ServiceAccount的认识:
查看系统中ServiceAccount对象,能够看到一个名为default的Service Account对象,包含一个名为default-token-xxx的Secret,这个Secret同时是“Mountable secrets”,代表他是须要被Mount到Pod上的。
default-token-xxx包括三个数据项:
联想到“Mountable secrets”的标记,以及以前看到的Pod中的三个文件的文件名:每一个namespace下有一个名为default的默认的ServiceAccount对象,这个ServiceAccount里有一个名为Tokens的能够做为Volume同样被Mount到Pod里的Secret,当Pod启动时这个Secret会被自动Mount到Pod的指定目录下,用来协助完成Pod中的进程访问API Server时的身份鉴权过程。
一个ServiceAccount能够包括多个Secrets对象:
若是一个Pod在定义时没有指定spec.service.AccountName属性,则系统会自动为其赋值为“Default”,即便用同一namespace下默认的ServiceAccount,若是某个Pod须要使用非default的ServiceAccount,须要在定义时指定:
apiVersion:v1
kind:Pod
metadata:
name:mypod
spec:
containers:
- name:mycontainer
image:
serviceAccountName:myserviceaccount
Kubernetes之因此要建立两套独一的帐号系统,缘由以下:
下面分析Service Account与Secret相关的一些运行机制:
Controller manager建立了ServiceAccountController与Token Controllerl两个安全相关的控制器。其中ServiceAccountController一直监听Service Account和Namespace的事件,若是一个Namespace中没有default Service Account,那么Service Account Controller就会为该Namespace建立一个默认的(default)的Service Account,这就是咱们以前看到的每一个namespace下都有一个名为default的ServiceAccount的缘由。
若是Controller manager进程在启动时指定了API Server私钥(service-account-private-key-file)参数,那么Controller manager会建立Token Controller。Token Controller也监听Service Account的事件,若是发现新建的Service Account里没有对应的Service Account Secret,则会用API Server私钥建立一个Token(JWT Token),并用该Token、CA证书Namespace名称等三个信息产生一个新的Secret对象,而后放入刚才的Service Account中;若是监听到的事件是删除Service Account事件,则自动删除与该Service Account相关的全部Secret。此外,Token Controller对象同时监听Secret的建立、修改和删除事件,并根据事件的不一样作不一样的处理。
当咱们在API Server的鉴权过程当中启用了Service Account类型的准入控制器,即在kube-apiserver的启动参数中包括下面的内容时:
则针对Pod新增或修改的请求,Service Account准入控制器会验证Pod里Service Account是否合法。
综上所述,ServiceAccount正常运行须要如下几个控制器:
Secret主要做用是保管私密数据,好比密码、OAuth Tokens、SSH Keys等信息。将这些私密信息放在Secret对象中比直接放在Pod或Docker Image中要更安全,也便于使用和分发。
secret.yaml
apiVersion:v1
kind:Secret
metadata:
name:mysecret
type: Opaque
data:
password:dmfsdWUtMg0k
username:dmfsdWUtMg0k
kubectl create -f secret.yaml
在上面的data域中的各子域的值必须为BASE64编码值,其中password域和username域BASE64编码前的值分别为value-1和value-2。一旦secret被建立,能够经过如下三个方式使用它:
apiVersion:v1
kind:Pod
metadata:
name:mypod
namespace:myns
spec:
containers:
- name:mycontainer
image:redis
volumeMounts:
- name:foo
mountPath:“/etc/foo”
readOnly:true
volumes:
- name:foo
secret:
secretName:mysecret
image-pull-secret.yaml:
apiVersion:v1
kind:Secret
metadata:
name:myregistrykey
data:
.dockercfg:xxx
type:kubernetes.io/dockercfg
pods.yaml
apiVersion:v1
kind:Pod
metadata:
name:mypod2
spec:
containers:
- name:foo
image:xxxxxx:v1
imagePullSecrets:
- name:myregistrykey
每一个单独的Secret大小不能超过1M,Kubernetes不鼓励建立大尺寸的Secret,由于若是使用大尺寸的Secret,则将大量占用API Server和kubelet的内存。固然建立许多小的Secret也能耗尽API Server和kubelet的内存。
在使用Mount方式挂载Secret时,Container中Secret的“data”域的各个域的key值做为目录中的文件,Value值被BASE64编码后存储在相应的文件中。前面的例子中建立的Secret,被挂载到一个叫作mycontainer的container中,在该container中能够经过命令查看所生产的文件和文件中的内容:
username
password
value-1
value-2
咱们能够经过Secret保管其余系统的敏感信息(好比数据库用户名和密码),并以Mount的方式将Secret挂载到Container中,而后经过访问目录中的文件的方式获取该敏感信息。当Pod被API Server建立时,API Server不会校验该Pod引用的Secret是否存在。一旦这个Pod被调度,则Kubelet将试着获取Secret的值。若是Secret不存在或暂时没法链接到API Server,则kubelet将按必定的时间间隔按期重试获取该Secret,并发送一个Event来解释Pod没有启动的缘由。一旦Secret被Pod获取,则Kubelet将建立并Mount包含Secret的Volume。只有全部的Volume被Mount后,Pod中的Container才会被启动。在kubelet启动Pod中container后,Container中和Secret相关的Volume将不会被改变,即便Secret自己被修改了。为了使用更新后的Secret,必须删除旧的Pod,并从新建立一个新的Pod,所以更新Secret的流程和部署一个新的Image是同样的。