Kubernetes API 访问控制

用户通过 kubectl、客户端库或者通过发送 REST 请求访问 API。 用户(自然人)和 Kubernetes 服务账户 都可以被授权进行 API 访问。 请求到达 API 服务器后会经过几个阶段,具体说明如图:

Diagram of request handling steps for Kubernetes API request

传输层安全

在典型的 Kubernetes 集群中,API 通过 443 端口提供服务。 API 服务器会提供一份证书。 该证书一般是自签名的, 所以用户机器上的 $USER/.kube/config 目录通常 包含该 API 服务器证书的根证书,用来代替系统默认根证书。 当用户使用 kube-up.sh 创建集群时,该证书通常会被自动写入用户的 $USER/.kube/config。 如果集群中存在多个用户,则创建者需要与其他用户共享证书。

认证

一旦 TLS 连接建立,HTTP 请求就进入到了认证的步骤。即图中的步骤 1 。 集群创建脚本或集群管理员会为 API 服务器配置一个或多个认证模块。 更具体的认证相关的描述详见这里

认证步骤的输入是整个 HTTP 请求,但这里通常只是检查请求头和 / 或客户端证书。

认证模块支持客户端证书,密码和 Plain Tokens, Bootstrap Tokens,以及 JWT Tokens(用于服务账户)。

(管理员)可以同时设置多种认证模块,在设置了多个认证模块的情况下,每个模块会依次尝试认证, 直到其中一个认证成功。

在 GCE 平台中,客户端证书,密码和 Plain Tokens,Bootstrap Tokens,以及 JWT Tokens 同时被启用。

如果请求认证失败,则请求被拒绝,返回 401 状态码。 如果认证成功,则被认证为具体的 username,该用户名可供随后的步骤中使用。一些认证模块还提供了用户的组成员关系,另一些则没有。

尽管 Kubernetes 使用“用户名”来进行访问控制和请求记录,但它实际上并没有 user 对象,也不存储用户名称或其他相关信息。

授权

当请求被认证为来自某个特定的用户后,该请求需要被授权。 即图中的步骤 2

请求须包含请求者的用户名,请求动作,以及该动作影响的对象。 如果存在相应策略,声明该用户具有进行相应操作的权限,则该请求会被授权。

例如,如果 Bob 有如下策略,那么他只能够读取 projectCaribou 命名空间下的 pod 资源:

  1. {
  2. "apiVersion": "abac.authorization.kubernetes.io/v1beta1",
  3. "kind": "Policy",
  4. "spec": {
  5. "user": "bob",
  6. "namespace": "projectCaribou",
  7. "resource": "pods",
  8. "readonly": true
  9. }
  10. }

如果 Bob 发起以下请求,那么请求能够通过授权,因为 Bob 被允许访问 projectCaribou 命名空间下的对象:

  1. {
  2. "apiVersion": "authorization.k8s.io/v1beta1",
  3. "kind": "SubjectAccessReview",
  4. "spec": {
  5. "resourceAttributes": {
  6. "namespace": "projectCaribou",
  7. "verb": "get",
  8. "group": "unicorn.example.org",
  9. "resource": "pods"
  10. }
  11. }
  12. }

如果 Bob 对 projectCaribou 命名空间下的对象发起一个写(create 或者 update)请求,那么它的授权会被拒绝。 如果 Bob 请求读取 (get)其他命名空间,例如 projectFish 下的对象,其授权也会被拒绝。

Kubernetes 的授权要求使用通用的 REST 属性与现有的组织或云服务提供商的访问控制系统进行交互。 采用 REST 格式是必要的,因为除 Kubernetes 外,这些访问控制系统还可能与其他的 API 进行交互。

Kubernetes 支持多种授权模块,例如 ABAC 模式,RBAC 模式和 Webhook 模式。 管理员创建集群时,会配置 API 服务器应用的授权模块。 如果多种授权模式同时被启用,Kubernetes 将检查所有模块,如果其中一种通过授权,则请求授权通过。 如果所有的模块全部拒绝,则请求被拒绝(HTTP 状态码 403)。

要了解更多的 Kubernetes 授权相关信息,包括使用授权模块创建策略的具体说明等,可参考授权概述

准入控制

准入控制模块是能够修改或拒绝请求的软件模块。 作为授权模块的补充,准入控制模块会访问被创建或更新的对象的内容。 它们作用于对象的创建,删除,更新和连接(proxy)阶段,但不包括对象的读取。

可以同时配置多个准入控制器,它们会按顺序依次被调用。

即图中的步骤 3

与认证和授权模块不同的是,如果任一个准入控制器拒绝请求,那么整个请求会立即被拒绝。

除了拒绝请求外,准入控制器还可以为对象设置复杂的默认值。

可用的准入控制模块描述 如下

一旦请求通过所有准入控制器,将使用对应 API 对象的验证流程对其进行验证,然后写入对象存储 (如步骤 4)。

API 的端口和 IP

上述讨论适用于发送请求到 API 服务器的安全端口(典型情况)。
实际上 API 服务器可以通过两个端口提供服务:

默认情况下,API 服务器在 2 个端口上提供 HTTP 服务:

  1. Localhost Port:

    1. - 用于测试和启动,以及管理节点的其他组件
    2. scheduler, controller-manager)与 API 的交互
    3. - 没有 TLS
    4. - 默认值为 8080,可以通过 `--insecure-port` 标记来修改。
    5. - 默认的 IP 地址为 localhost 可以通过 `--insecure-bind-address` 标记来修改。
    6. - 请求会 **绕过** 认证和鉴权模块。
    7. - 请求会被准入控制模块处理。
    8. - 其访问需要主机访问的权限。
  2. Secure Port:

    1. - 尽可能使用该端口访问
    2. - 应用 TLS 可以通过 `--tls-cert-file` 设置证书, 通过 `--tls-private-key-file` 设置私钥。
    3. - 默认值为 6443,可以通过 `--secure-port` 标记来修改。
    4. - 默认 IP 是首个非本地的网络接口地址,可以通过 `--bind-address` 标记来修改。
    5. - 请求会经过认证和鉴权模块处理。
    6. - 请求会被准入控制模块处理。
    7. - 要求认证和授权模块正常运行。

通过 kube-up.sh 创建集群时, 对 Google Compute Engine(GCE) 和一些其他的云供应商来说, API 通过 443 端口提供服务。 对 GCE 而言,项目上配置了防火墙规则,允许外部的 HTTPS 请求访问 API,其他(厂商的)集群设置方法各不相同。