本文将主要分享以下三方面的内容:

  1. Kubernetes API 请求访问控制
  2. Kubernetes 认证
  3. Kubernetes RBAC
  4. Security Context 的使用

一、Kubernetes API 请求访问控制


访问控制

大家都知道访问控制是云原生中的一个重要组成部分。也是一个 Kubernetes 集群在多租户环境下必须要采取的一个基本的安全架构手段。

Kubernetes 安全之访问控制 API 请求访问控制和认证_访问控制

那么在概念上可以抽象的定义为谁在何种条件下可以对什么资源做什么操作。这里的资源就是在 Kubernetes 中我们熟知的:Pod、 ConfigMaps、Deployment、Secrets 等等这样的资源模型。 

 Kubernetes API 请求

Kubernetes 安全之访问控制 API 请求访问控制和认证_客户端_02

由上图来介绍一下 Kubernetes API 的请求从发起到其持久化入库的一个流程。

首先看一下请求的发起,请求的发起分为两个部分:

  • 第一个部分是人机交互的过程。 是大家非常熟悉的用 kubectl 对 api-server 的一个请求过程;
  • 第二个部分是 Pod 中的业务逻辑与 api-server 之间的交互。

当我们的 api-server 收到请求后,就会开启访问控制流程。这里面分为三个步骤:  

  • Authentication 认证阶段:判断请求用户是否为能够访问集群的合法用户。如果用户是个非法用户,那 api-server 会返回一个 401 的状态码,并终止该请求;
[root@master pki]# kubectl get ep
NAME ENDPOINTS AGE
fuseim.pri-ifs <none> 10d
kubernetes 192.168.0.2:6443 12d
[root@master pki]# curl -I 192.168.0.2:6443
HTTP/1.0 400 Bad Request
  • 如果用户合法的话,我们的 api-server 会进入到访问控制的第二阶段 Authorization:鉴权阶段。在该阶段中 api-server 会判断用户是否有权限进行请求中的操作。如果无权进行操作,api-server 会返回 403 的状态码,并同样终止该请求;
  • 如果用户有权进行该操作的话,访问控制会进入到第三个阶段:AdmissionControl。在该阶段中 api-server 的 Admission Control 会判断请求是否是一个安全合规的请求。如果最终验证通过的话,访问控制流程才会结束。

 此时我们的请求将会转换为一个 Kubernetes objects 相应的变更请求,最终持久化到 ETCD 中。 

HTTP常见的错误码

4xx:客户端发生了错误

  • 常见的是资源找不到了(404)
  • 资源请求需要认证认证失败(401)
  • 认证成功但是权限不够(403)

二、Kubernetes 认证


Kubernetes 中的用户模型

对于认证来说,首先我们要确定请求的发起方是谁。并最终通过认证过程将其转换为一个系统可识别的用户模型用于后期的鉴权,那么先来看一下 Kubernetes 中的用户模型。

1. Kubernetes 没有自身的用户管理能力

什么是用户管理能力呢?我们无法像操作 Pod 一样,通过 API 的方式创建删除一个用户实例。同时我们也无法在 ETCD 中找到用户对应的存储对象。

2. Kubernetes 中的用户通常是通过请求凭证设置

在 Kubernetes 的访问控制流程中用户模型是如何产生的呢?答案就在请求方的访问控制凭证中,也就是我们平时使用的 kube-config 中的证书,或者是 Pod 中引入的 ServerAccount。经过 Kubernetes 认证流程之后,api-server 会将请求中凭证中的用户身份转化为对应的 User 和 Groups 这样的用户模型。在随后的鉴权操作和审计操作流程中,api-server 都会使用到改用户模型实例。

3、Kubernetes支持的请求认证方式主要包括:

  • Basic 认证

该认证方式下,管理员会将 Username 和 Password 组成的白名单放置在 api-server 读取的静态配置文件上面进行认证,该方式一般用于测试场景,在安全方面是不推荐且不可拓展的一种方式。

  • X509 证书认证

该方式是 api-server 中相对应用较多的使用方式,首先访问者会使用由集群 CA 签发的,或是添加在 api-server Client CA 中授信 CA 签发的客户端证书去访问 api-server。api-server 服务端在接收到请求后,会进行 TLS 的握手流程。除了验证证书的合法性,api-server 还会校验客户端证书的请求源地址等信息。开启双向认证,X509 认证是一个比较安全的方式,也是 Kubernetes 组件之间默认使用的认证方式,同时也是 kubectl 客户端对应的 kube-config 中经常使用到的访问凭证。

  • Bearer Tokens(JSON Web Tokens)
  • Service Account
  • OpenID Connect
  • Webhooks

该方式的 Tokens 是通用的 JWT 的形式,其中包含了签发者、用户的身份、过期时间等多种元信息。它的认证方式也是常见的私钥加签,公钥验签的一个基本流程。基于 Token 的认证使用场景也很广泛,比如 Kubernetes Pod 应用中经常使用到的 Service Account,其中就会自动绑定一个签名后的 JWT Token 用于请求 api-server。

另外 api-server 还支持基于 OpenID 协议的 Token 认证,可以通过对 api-server 的配置连接一个指定的外部 IDP,同时可以通过 Keycloak,Dex 这样的开源服务来管理 IDP,请求者可以按照自己熟悉的方式在原身份认证服务上进行登录认证,并最终返回一个相应的 JWT token,为了后面的 api-server 的鉴权流程。

除此之外,还可以使用 Webhooks 的方式,将请求的 Token 发送到指定外部服务进行 Token 的验签。

Kubernetes 安全之访问控制 API 请求访问控制和认证_字段_03

对于一个集群证书体系来说,认证机构 (CA) 是一个非常重要的证书对。它会被默认放置在集群 Master 节点上的 /etc/Kubernetes/pki/ 目录下。集群中所有组件之间的通讯用到的证书,其实都是由集群根 CA 来签发的。在证书中有两个身份凭证相关的重要字段:一个是 CN,一个是 O。 

[root@master ~]# cd /etc/kubernetes/pki/

[root@master pki]# ls
apiserver.crt apiserver-kubelet-client.crt ca.crt front-proxy-ca.crt front-proxy-client.crt sa.key
apiserver.key apiserver-kubelet-client.key ca.key front-proxy-ca.key front-proxy-client.key sa.pub
cat > lulei-csr.json <<EOF
{
"CN": "lulei",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF

另外可以通过 openssl 命令来进行证书的解析。上图右侧可以看到,通过 Subject 中的 O 和 CN 字段可以查看对应的信息。

Kubernetes 安全之访问控制 API 请求访问控制和认证_访问控制_04

上面每一个组件证书都有自己指定的 Common Name 和 Organization 用于特定角色的绑定。这样的设置可以使各系统组件只绑定自身功能范围内的角色权限。从而保证了每个系统组件自身权限的最小化。 

证书签发 API


Kubernetes 安全之访问控制 API 请求访问控制和认证_访问控制_05

Kubernetes 集群本身就提供了证书签发的 API,而在集群的创建过程中,像 kube-admin 这样的集群安装工具,会基于不同的 CSR 签发请求调用 api-server 对应接口。此时 api-server 会根据请求,以这种 csr 资源模型的形式创建对应的签发请求实例。刚开始创建的签发实例都会处于 pending 的状态,直到有权限的管理员进行审批后,这个 csr 才会处于 approved 的状态,请求对应的证书就会被签发。

通过上图右侧中的命令可以来查看相应的证书内容信息。

签发用户证书


Kubernetes 安全之访问控制 API 请求访问控制和认证_客户端_06

首先开发人员需用通过 openssl 等证书工具生成私钥,然后创建对应的 X509 csr 请求文件,需要在 sbuj 字段中指定用户 user 和组 group,最后通过 API 创建 K8s csr 实例并等待管理员审批。

对于集群管理员,他可以直接读取集群根 CA,并通过 X509 的 csr 请求文件签发证书,所以它无需定义或审批 csr 实例。上图中最后一行是一个 openssl 签发示例,命令中需要指明 csr 和 ca.crt 的文件路径,以及签发证书的过期时间信息。

另外各个云厂商也会基于登录用户和目标集群直接生成访问凭证,一键化流程,方便用户的使用。

Service Accounts


Kubernetes 安全之访问控制 API 请求访问控制和认证_kubernetes_07

除了证书认证之外,Service Account 也是 api-server 中应用比较广泛的一种方式。对于 Service Account 来说,它是 Kub 中唯一能够通过 API 方式管理的 APIService 访问凭证,其他特性在上图中可以看到。

图中也给出了一些使用 kubectl 进行 Service Account API 相关增删改查的示例,同时我们也为已经存在的 Service Account 主动的创建其 Token 对应的 Secret,有兴趣的同学可以在 Kubernetes 集群中操作执行一下。

接着看一下 Service Account 的使用。

Kubernetes 安全之访问控制 API 请求访问控制和认证_客户端_08

首先可以通过 get secrets 命令查看对应 Service Account 中对应的 secret,其中 token 字段经过了 base64 位编码的 JWT 格式认证 token。 

Kubernetes 安全之访问控制 API 请求访问控制和认证_访问控制_09

spec:
containers:
- image: nginx:1.14.2
...............................................
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-qs2lj
readOnly: true

serviceAccount: default
serviceAccountName: default
....................................................
- name: default-token-qs2lj
secret:
defaultMode: 420
secretName: default-token-qs2lj

 在部署一个应用时,可以通过 Template-spec-serviceAccountName 字段声明需要使用的 Service Account 名称。注意如果是在 Pod 创建过程中,发现制定的 ServiceAccount 不存在,则该 Pod 创建过程会被终止。

在生成的 Pod 模板中可以看到指定 Service Account 对应的 secret 中的 CA namespace 和认证 token 会分别以文件的形式挂载到容器中的指定目录下,另外对于已经创建的 Pod,我们不能更新其已经挂载的 ServiceAccount 内容。

# ls
ca.crt namespace token

生成 kubeconfig


kubeconfig 是用户本地连接 Kubernetes 集群使用的重要访问凭证,接着来介绍一下 kubeconfig 的配置和使用。