08 安全重点 认证和授权
本节我们将开始学习将 K8S 应用于生产环境中至关重要的一环,权限控制。当然,不仅是 K8S 对于任何应用于生产环境中的系统,权限管理或者说访问控制都是很重要的。
整体概览
通过前面的学习,我们已经知道 K8S 中几乎所有的操作都需要经过 kube-apiserver 处理,所以为了安全起见,K8S 为它提供了三类安全访问的措施。分别是:用于识别用户身份的认证(Authentication),用于控制用户对资源访问的授权(Authorization)以及用于资源管理方面的准入控制(Admission Control)。
下面的图基本展示了这一过程。来自客户端的请求分别经过认证,授权,准入控制之后,才能真正执行。
当然,这里说基本展示是因为我们可以直接通过 kubectl proxy 的方式直接通过 HTTP 请求访问 kube-apiserver 而无需任何认证过程。
另外,也可通过在 kube-apiserver 所启动的机器上,直接访问启动时 –insecure-port 参数配置的端口进行绕过认证和授权,默认是 8080。为了避免安全问题,也可将此参数设置为 0 以规避问题。注意:这个参数和 –insecure-bind-address 都已过期,并将在未来的版本移除。
认证(Authentication)
认证,无非是判断当前发起请求的用户身份是否正确。例如,我们通常登录服务器时候需要输入用户名和密码,或者 SSH Keys 之类的。
在讲认证前,我们应该先理一下 K8S 中的用户。
K8S 中有两类用户,一般用户及 Service Account。
- 一般用户:一般用户只能通过外部服务进行管理,由管理员进行私钥分发。这也意味着 K8S 中并没有任何表示一般用户的对象,所以一般用户是无法通过 API 直接添加到集群的。
- Service Account:由 K8S API 管理的用户,与特定的 NameSpace(命名空间)绑定。由 API Server 自动创建或者通过 API 手动进行创建。 同时,它会自动挂载到 Pod 中容器的 /var/run/secrets/kubernetes.io/serviceaccount/ 目录中,其中会包含 NameSpace token 等信息,并允许集群内进程与 API Server 进行交互。
对集群操作的 API 都是与用户相关联的,或者被视为匿名请求。匿名请求可通过 kube-apiserver 的 –anonymous-auth 参数进行控制,默认是开启的,匿名用户默认的用户名为 system:anonymous,所属组为 system:unauthenticated。
理完 K8S 中的用户,我们来看下 K8S 中的认证机制。
K8S 支持以下认证机制:
- X509 客户端证书:这个认证机制我们并不陌生,我们前面搭建集群时,虽然没有指定配置文件,但 kubeadm 已经添加了默认参数 –client-ca-file=/etc/kubernetes/pki/ca.crt 而在进行认证时,将会使用客户端证书 subject 的 CN 域(Common Name)用作用户名,O 域(Organization)用作组名。
- 引导 Token:这个我们也不会陌生,前面我们搭建集群时,当集群通过 kubeadm init 初始化完成后,将会展示一行提示,其中便携带着引导 Token。如果不使用 kubeadm 时,需要设置 –enable-bootstrap-token-auth=true。
- 静态 Token 文件:启动 Kube-apiserver 时,设置 –token-auth-file=SOMEFILE 并在请求时,加上 Authorization: Bearer TOKEN 的请求头即可。
- 静态密码文件:与静态 Token 文件类似,设置 –basic-auth-file=SOMEFILE 并在请求时,加上 Authorization: Basic BASE64ENCODED(USER:PASSWORD) 的头即可。
- Service Account Token:这是默认启用的机制,关于 Service Account 前面也已经介绍过了,不再赘述。
- OpenID:其实是提供了 OAuth2 的认证支持,像 Azure 或 Google 这类云厂商都提供了相关支持。
- 认证代理:主要是配合身份验证代理进行使用,比如提供一个通用的授权网关供用户使用。
- Webhook:提供 Webhook 配合一个远端服务器使用。
可选择同时开启多个认证机制。比如当我们使用 kubeadm 创建集群时,默认便会开启 X509 客户端证书和引导 Token 等认证机制。
授权(Authorization)
授权,也就是在验证当前发起请求的用户是否有相关的权限。例如,我们在 Linux 系统中常见的文件夹权限之类的。
授权是以认证的结果为基础的,授权机制检查用户通过认证后的请求中所包含的属性来进行判断。
K8S 支持多种授权机制,用户想要正确操作资源,则必须获得授权,所以 K8S 默认情况下的权限都是拒绝。当某种授权机制通过或者拒绝后,便会立即返回,不再去请求其他的授权机制;当所有授权机制都未通过时便会返回 403 错误了。
K8S 支持以下授权机制:
- ABAC(Attribute-Based Access Control):基于属性的访问控制,在使用时需要先配置 –authorization-mode=ABAC 和 –authorization-policy-file=SOME_FILENAME 。ABAC 本身设计是非常好的,但是在 K8S 中使用却有点过于繁琐,这里不再赘述。
- RBAC(Role-based access control):基于角色的访问控制,自 K8S 1.6 开始 beta,1.8 进入稳定版,已被大量使用。而当我们使用 kubeadm 安装集群的时候,默认将会添加 –authorization-mode=Node,RBAC 的参数,表示同时开启 Node 和 RBAC 授权机制。当然,如果你对 MongoDB 有所了解或者比较熟悉的话,这部分的内容就会很容易理解,因为 MongoDB 的权限控制也使用了 RBAC (Role-based access control)。
- Node:这是一种特殊用途的授权机制,专门用于对 kubelet 发出的 API 请求做授权验证。
- Webhook:使用外部的 Server 通过 API 进行授权校验,需要在启动时候增加 –authorization-webhook-config-file=SOME_FILENAME 以及 –authorization-mode=Webhook
- AlwaysAllow:默认配置,允许全部。
- AlwaysDeny:通常用于测试,禁止全部。
角色(Role)
上面提到了 RBAC,为了能更好的理解,我们需要先认识下 K8S 中的角色。K8S 中的角色从类别上主要有两类,Role 和 ClusterRole。
- Role:可以当作是一组权限的集合,但被限制在某个 Namespace 内(K8S 的 Namespace)。
- ClusterRole:对于集群级别的资源是不被 Namespace 所限制的,并且还有一些非资源类的请求,所以便产生了它。
当已经了解到角色后,剩下给用户授权也就只是需要做一次绑定即可。在 K8S 中将这一过程称之为 binding,即 rolebinding 和 clusterrolebinding。 我们来看下集群刚初始化后的情况:
可以看到默认已经存在了一些 role 和 rolebindings。 对于这部分暂且不做过多说明,我们来看下对于集群全局有效的 ClusterRole 。
可以看到 K8S 中默认已经有很多的 ClusterRole 和 clusterrolebindings 了,我们选择其中一个做下探究。
查看用户权限
我们一直都在使用 kubectl 对集群进行操作,那么当前用户是什么权限呢? 对应于 RBAC 中又是什么情况呢?
client-certificate-data 的部分默认是不显示的,而它的内容实际是通过 base64 加密后的证书内容。我们可以通过通过以下方式进行查看
根据前面认证部分的内容,我们知道当前的用户是 kubernetes-admin (CN 域),所属组是 system:masters (O 域) 。
我们看下 clusterrolebindings 中的 cluster-admin 。
重点内容在 roleRef 和 subjects 中,名为 cluster-admin 的 ClusterRole 与名为 system:masters 的 Group 相绑定。我们继续探究下它们所代表的含义。
先看看这个 ClusterRole 的实际内容:
rules 中定义了它所能操作的资源及对应动作,* 是通配符。
到这里,我们就可以得出结论了,当前用户 kubernetes-admin 属于 system:masters 组,而这个组与 cluster-admin 这个 ClusterRole 所绑定,所以用户也就继承了其权限。具备了对多种资源和 API 的相关操作权限。
实践:创建权限可控的用户
前面是通过实际用户来反推它所具备的权限,接下来我们开始实践的部分,创建用户并为它进行授权。
我们要创建的用户名为 backend 所属组为 dev。
创建 NameSpace
为了演示,这里创建一个新的 NameSpace ,名为 work。
创建用户
创建私钥
使用私钥生成证书请求。前面已经讲过关于认证的部分,在这里需要指定 subject 信息,传递用户名和组名
使用 CA 进行签名。K8S 默认的证书目录为 /etc/kubernetes/pki。
查看生成的证书文件
可以看到 CN 域和 O 域已经正确设置
添加 context
使用新用户测试访问
可以看到已经使用了新的 backend 用户,并且默认的 Namespace 设置成了 work。
创建 Role
我们想要让这个用户只具备查看 Pod 的权限。先来创建一个配置文件。
创建并查看已生成的 Role。
创建 Rolebinding
先创建一个配置文件。
创建并查看已生成的 Rolebinding 。
测试用户权限
可以看到用户已经具备查看 Pod 的权限,但并不能查看 Namespace 或者 deployment 等其他资源。当然,K8S 也内置了一种很方便的调试机制。
–as 是一种建立在 K8S 认证机制之上的机制,可以便于系统管理员验证授权情况,或进行调试。
你也可以仿照 ~/.kube/config 文件的内容,将当前生成的证书及私钥文件等写入到配置文件中,通过指定 KUBECONFIG 的环境变量,或者给 kubectl 传递 –kubeconfig 参数来使用。
总结
本节中,我们学习了 K8S 的认证及授权逻辑,K8S 支持多种认证及授权模式,可按需使用。通过 X509 客户端证书认证的方式使用比较方便也比较推荐,在客户端证书的 CN 域和 O 域可以指定用户名和所属组名。
RBAC 的授权模式现在使用最多,可以通过对 Role 和 subjects (可以是用户或组) 进行绑定,以达到授权的目的。
最后,我们实际新创建了一个用户,并对其授予了预期的权限。在此过程中也涉及到了 openssl 客户端的常规操作,在之后也会常常用到。
下节,我们将开始部署实际的项目到 K8S 中,逐步掌握生成环境中对 K8S 的使用实践。
PS: 也许你会觉得切换 Namespace 之类的操作很繁琐,有一个项目:kubectx 可帮你简化这些步骤,推荐尝试。