HTTPToken的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串—Token来表明客户身份的一种方式。在通常情况下,Token是一个很复杂的字符串,比如我们用私钥签名一个字符串后的数据就可以被当作一个Token。此外,每个Token对应一个用户名,存储在APIServer能访问的一个文件中。当客户端发起API调用请求时,需要在HTTPHeader里放入Token,这样一来,APIServer就能识别合法用户和非法用户了HTTPBase认证:HTTP是无状态的,浏览器和Web服务器之间可以通过Cookie来进行身份识别。桌面应用程序(比如新浪桌面客户端、SkyDrive客户端、命令行程序)一般不会使用Cookie,那么它们与Web服务器之间是如何进行身份识别的呢?这就用到了HTTPBase认证,这种认证方式是把“用户名+冒号+密码”用BASE64算法进行编码后的字符串放在HTTPRequest中的HeaderAuthorization域里发送给服务端,服务端在收到后进行解码,获取用户名及密码,然后进行用户身份鉴权
RBAC(Role-BasedAccessControl,基于角色的访问控制)在Kubernetes的1.5版本中引入,在1.6版本时升级为Beta版本,在1.8版本时升级为GA
◎对集群中的资源和非资源权限均有完整的覆盖。◎整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作。◎可以在运行时进行调整,无须重新启动APIServer。
1.RBAC的API资源对象说明RBAC引入了4个新的顶级资源对象:Role、ClusterRole、RoleBinding和ClusterRoleBinding。同其他API资源对象一样,用户可以使用kubectl或者API调用等方式操作这些资源对象1)角色(Role)一个角色就是一组权限的集合,这里的权限都是许可形式的,不存在拒绝的规则。在一个命名空间中,可以用角色来定义一个角色,如果是集群级别的,就需要使用ClusterRole了
例如,在下面的例子中,虽然secret-reader是一个集群角色,但是因为使用了RoleBinding,所以dave只能读取development命名空间中的secret
3.常用的角色示例.注意,下面的例子只展示了rules部分的内容(1)允许读取核心API组中的Pod资源:
(2)允许读写extensions和apps两个API组中的deployment资源:
(3)允许读取pods及读写jobs
(4)允许读取一个名为my-config的ConfigMap(必须绑定到一个RoleBinding来限制到一个Namespace下的ConfigMap)
(5)读取核心组的Node资源(Node属于集群级的资源,所以必须存在于ClusterRole中,并使用ClusterRoleBinding进行绑定):
4.常见的角色绑定示例.注意,在下面的例子中只包含subjects部分的内容。
(1)用户名alice@example.com:
(2)组名frontend-admins:
(3)kube-system命名空间中的默认ServiceAccount:
(4)qa命名空间中的所有ServiceAccount:
(5)所有ServiceAccount:
(6)所有认证用户(Kubernetes1.5以上版本):
(7)所有未认证用户(Kubernetes1.5以上版本):
(8)全部用户(Kubernetes1.5以上版本):
对系统角色的说明如表6.1所示
有些默认角色不是以“system:”为前缀的,这部分角色是针对用户的。其中包含超级用户角色(cluster-admin),有的用于集群一级的角色(cluster-status),还有针对Namespace的角色(admin、edit、view)
RBACAPI拒绝用户通过编辑角色或者角色绑定进行提升权限。这一限制是在API层面做出的,因此即使RBAC没有启用也仍然有效
用户要对角色进行创建或更新操作,需要满足下列至少一个条件:
(1)拥有一个角色的所有权限,且与该角色的生效范围一致(如果是集群角色,则是集群范围;如果是普通角色,则可能是同一个命名空间或者整个集群)(2)为用户显式授予针对该角色或集群角色的提权(escalate)操作的权限(要求Kubernetes1.12及以上版本)
对Kubernetes1.10及以上版本设置如下
对Kubernetes1.9及以下版本设置如下:
◎这个Token的内容来自Pod里指定路径下的一个文件(/run/secrets/kubernetes.io/serviceaccount/token),这种Token是动态生成的,确切地说,是由KubernetesController进程用APIServer的私钥(--service-account-private-key-file指定的私钥)签名生成的一个JWTSecret。◎这个Token的内容来自Pod里指定路径下的一个文件(/run/secrets/kubernetes.io/serviceaccount/token),这种Token是动态生成的,确切地说,是由KubernetesController进程用APIServer的私钥(--service-account-private-key-file指定的私钥)签名生成的一个JWTSecret。◎在官方提供的客户端REST框架代码里,通过HTTPS方式与APIServer建立连接后,会用Pod里指定路径下的一个CA证书(/run/secrets/kubernetes.io/serviceaccount/ca.crt)验证APIServer发来的证书,验证是否为CA证书签名的合法证书。◎APIServer在收到这个Token以后,采用自己的私钥(实际上是使用service-accountkey-file参数指定的私钥,如果没有设置此参数,则默认采用tls-private-key-file指定的参数,即自己的私钥)对Token进行合法性验证。
我们接下来继续分析在上面的认证过程中所涉及的Pod中的以下三个文件。◎/run/secrets/kubernetes.io/serviceaccount/token。◎/run/secrets/kubernetes.io/serviceaccount/ca.crt。◎/run/secrets/kubernetes.io/serviceaccount/namespace(客户端采用这里指定的namespace作为参数调用KubernetesAPI)。
这三个文件由于参与到Pod进程与APIServer认证的过程中,起到了类似secret(私密凭据)的作用,所以它们被称为KubernetesSecret对象。Secret从属于ServiceAccount资源对象,属于ServiceAccount的一部分,在一个ServiceAccount对象里面可以包括多个不同的Secret对象,分别用于不同目的的认证活动
查看系统中的ServiceAccount对象,看到有一个名为default的ServiceAccount对象,包含一个名为default-token-77oyg的Secret,这个Secret同时是Mountablesecrets,表明它是需要被挂载到Pod上的default-token-77oyg包含三个数据项,分别是token、ca.crt、namespace。联想到Mountablesecrets的标记,以及之前看到的Pod中的三个文件的文件名,我们恍然大悟:在每个Namespace下都有一个名为default的默认ServiceAccount对象,在这个ServiceAccount里面有一个名为Tokens的可以当作Volume被挂载到Pod里的Secret,当Pod启动时,这个Secret会自动被挂载到Pod的指定目录下,用来协助完成Pod中的进程访问APIServer时的身份鉴权
其中:(1)名为Tokens的Secret用于访问APIServer的Secret,也被称为ServiceAccountSecret。(2)名为imagePullSecrets的Secret用于下载容器镜像时的认证过程,通常镜像库运行在Insecure模式下,所以这个Secret为空。(3)用户自定义的其他Secret,用于用户的进程。如果一个Pod在定义时没有指定spec.serviceAccountName属性,则系统会自动为其赋值为default,即大家都使用同一个Namespace下的默认ServiceAccount。如果某个Pod需要使用非default的ServiceAccount,则需要在定义时指定:
Kubernetes之所以要创建两套独立的账号系统,原因如下。◎User账号是给人用的,ServiceAccount是给Pod里的进程使用的,面向的对象不同。◎User账号是全局性的,ServiceAccount则属于某个具体的Namespace。◎通常来说,User账号是与后端的用户数据库同步的,创建一个新用户通常要走一套复杂的业务流程才能实现,ServiceAccount的创建则需要极轻量级的实现方式,集群管理员可以很容易地为某些特定任务创建一个ServiceAccount。◎对于这两种不同的账号,其审计要求通常不同。◎对于一个复杂的系统来说,多个组件通常拥有各种账号的配置信息,ServiceAccount是Namespace隔离的,可以针对组件进行一对一的定义,同时具备很好的“便携性”。
Secret的主要作用是保管私密数据,比如密码、OAuthTokens、SSHKeys等信息。将这些私密信息放在Secret对象中比直接放在Pod或DockerImage中更安全,也更便于使用和分发
在上面的例子中,data域的各子域的值必须为BASE64编码值,其中password域和username域BASE64编码前的值分别为value-1和value-2
一旦Secret被创建,就可以通过下面三种方式使用它
(1)在创建Pod时,通过为Pod指定ServiceAccount来自动使用该Secret(2)通过挂载该Secret到Pod来使用它。(3)在Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecrets来引用它。第1种使用方式主要用在APIServer鉴权方面.下面的例子展示了第2种使用方式:将一个Secret通过挂载的方式添加到Pod的Volume中:
每个单独的Secret大小不能超过1MB,Kubernetes不鼓励创建大的Secret,因为如果使用大的Secret,则将大量占用APIServer和kubelet的内存。当然,创建许多小的Secret也能耗尽APIServer和kubelet的内存
若想启用PodSecurityPolicy机制,则需要在kube-apiserver服务的启动参数--enable-admission-plugins中进行设置
创建一个PodSecurityPolicy,配置文件psp-non-privileged.yaml的内容如下
在PodSecurityPolicy对象中可以设置下列字段来控制Pod运行时的各种安全策略
结果为允许Pod访问宿主机上以“/foo”为前缀的路径,包括“/foo”“/foo/”“/foo/bar”等,但不能访问“/fool”“/etc/foo”等路径,也不允许通过“/foo/../”表达式访问/foo的上层目录(7)FSGroup:设置允许访问某些Volume的GroupID范围,可以将规则(rule字段)设置为MustRunAs、MayRunAs或RunAsAny。◎MustRunAs:需要设置GroupID的范围,例如1~65535,要求Pod的securityContext.fsGroup设置的值必须属于该GroupID的范围◎MayRunAs:需要设置GroupID的范围,例如1~65535,不强制要求Pod设置securityContext.fsGroup。◎RunAsAny:不限制GroupID的范围,任何Group都可以访问Volume。(8)ReadOnlyRootFilesystem:要求容器运行的根文件系统(rootfilesystem)必须是只读的。(9)allowedFlexVolumes:对于类型为flexVolume的存储卷,设置允许使用的驱动类型,例子如下。
例2:要求Pod运行用户为非特权用户;禁止提升权限;不允许使用宿主机网络、端口号、IPC等资源;限制可以使用的Volume类型,等等
然后创建一个ClusterRoleBinding与用户和ServiceAccount进行绑定