22. Kubernetes安全之访问控制

本文由 CNCF + Alibaba 云原生技术公开课 整理而来

Kubernetes API 请求访问控制

  • 访问控制:

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

在这里插入图片描述

访问控制,在概念上可以抽象的定义为谁在何种条件下可以对什么资源做什么操作。这里的资源就是在 Kubernetes 中熟知的:PodConfigMapDeploymentSecret 等等这样的资源对象。

  • Kubernetes API 请求:

在这里插入图片描述

Kubernetes API 的请求从发起到其持久化入库的一个流程:

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

第一个部分是人机交互的过程,就是用 kubectl 对 Api-Server 的一个请求过程;

第二个部分是 Pod 中的业务逻辑与 Api-Server 之间的交互。

Api-Server 收到请求后,就会开启访问控制流程。这里面分为三个步骤:

Authentication 认证阶段:判断请求用户是否为能够访问集群的合法用户。如果用户是合法用户,Api-Server 会进入到访问控制的第二阶段;否则 Api-Server 会返回一个 401 的状态码,并终止该请求;

Authentication 鉴权阶段:在该阶段中 Api-Server 会判断用户是否有权限进行请求中的操作。如果用户有权进行该操作的话,访问控制会进入到第三个阶段;否则 Api-Server 会返回 403 的状态码,并终止该请求;

AdmissionControl 阶段:在该阶段中 Api-Server 的 Admission Control 会判断请求是否是一个安全合规的请求。如果最终验证通过的话,访问控制流程才会结束。

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


Kubernetes 认证

  • Kubernetes 中的用户模型:

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

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

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

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

    在 Kubernetes 的访问控制流程中用户模型是如何产生的呢?答案就在请求方的访问控制凭证中,也就是平时使用的 kube-config 中的证书,或者是 Pod 中引入的 ServerAccount

    经过 Kubernetes 认证流程之后,Api-Server 会将请求中凭证中的用户身份转化为对应的 UserGroups 这样的用户模型。在随后的鉴权操作和审计操作流程中,Api-Server 都会使用到改用户模型实例。

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

    Basic 认证:

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

    X509 证书认证:

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

  • X509 证书认证:

在这里插入图片描述

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

在这里插入图片描述

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

  • 证书签发 API:

在这里插入图片描述

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

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

  • 签发用户证书:

在这里插入图片描述

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

对于集群管理员,他可以直接读取集群根 CA,并通过 X509 的 csr 请求文件签发证书,所以它无需定义或审批 csr 实例。

上图中最后一条命令是一个 openssl 签发示例,命令中需要指明 csr 和 ca.crt 的文件路径,以及签发证书的过期时间信息。

  • ServiceAccount

在这里插入图片描述

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

图中也给出了一些使用 kubectl 进行 ServiceAccount API 相关增删改查的示例,同时也为已经存在的 ServiceAccount 主动的创建其 Token 对应的 Secret

kubectl get secrets build-robot -o yaml
apiVersion: v1
kind: Secret
metadata:
  # ...
type: kubernetes.io/service-account-token
data:
  ca.crt: $(CA DATA...)
  namespace: dGVzdA==
  token: $(JSON Web Token signed by API server)

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

ServiceAccount 在应用中的挂载方式:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-basic
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        iamge: nginx:latest
      serviceAccountName: build-robot

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

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

  • 生成 kubeconfig

kubeconfig 是用户本地连接 Kubernetes 集群使用的重要访问凭证。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-py042kwJ-1611658474585)(8FFA3AB12F284EF9938BDA7DB5209984)]

  • 使用 kubeconfig

在这里插入图片描述


Kubernetes 鉴权 - RBAC

当一个请求在完成 Api-Server 认证后,可以认为它是一个合法的用户,那么如何控制该用户在集群中的哪些 Namespace 中访问哪些资源,对这些资源又能进行哪些操作呢?

这就由访问控制的第二步 Kubernetes 鉴权来完成。Api-Server 本身支持多种鉴权方式,在安全上主要推荐的鉴权方式是 RBAC

  • RBAC 鉴权三要素:

在这里插入图片描述

第一要素是 Subjects,也就是主体。可以是开发人员、集群管理员这样的自然人,也可以是系统组件进程,或者是 Pod 中的逻辑进程;

第二个要素是 API Resource,也就是请求对应的访问目标。在 Kubernetes 集群中也就是各类资源;

第三要素是 Verbs,对应为请求对象资源可以进行哪些操作,包括增删改查、list、get、watch 等。
  • RBAC 权限粒度:

在整个 RBAC 策略定义下,还需要将这个角色绑定到一个具体的控制域内,就是 Kubernetes 的命名空间。通过 Namespace 可以将 Kubernetes Api 资源限定在不同的作用域内。从而帮助实现在一个多租户集群中,对用户进行逻辑上的隔离。

在这里插入图片描述

需要注意的是,如果不进行任何的权限绑定,RBAC 会拒绝所有访问。

通常 RBAC 会进行对 Api-Server 的细粒度访问控制,但是这个细粒度是个相对的概念,RBAC 是面向模型级别的绑定。它不能绑定到 Namespace 中的一个具体的 object 实例,更不能绑定到指定资源的任意一个 field。

RBAC 对访问权限的控制粒度上,它可以细化到 Kubernetes Api 的 subresources 级别。比如针对一个访问者,可以控制其在指定 Namespace 下对 nodes/status 模型的访问。

  • RBAC - Role

在这里插入图片描述

Role(角色),它定义了用户在指定的 Kubernetes 命名空间资源上可以进行哪些操作。比如可以指定一个 NamespacePod 的只读权限,同时还可以定义一个 namespace 管理员权限,它具有对这个命名空间下所有对象资源的所有操作权限。

pod-access Role yaml 文件示例:

apiVerison: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-access
  namespace: test
rules:
- apiGroups: [""]
  resources: ["pods", "pods/attach"]
  verbs: ["get", "list", "watch"]

文件解析:

apiVerison: rbac.authorization.k8s.io/v1        表示 Role 当前所属的组是 rbac.authorization.k8s.io,版本是 v1

kind        表示 Kubernetes 资源类型是 Role

metadata    表示 Role 的元数据,元数据通常包含 name、namespace 等

rules       表示 Role 的规则,apiGroups 表示目标资源的 apiGroups 名称;resources 表示 Role 可以访问的资源;verbs 表示 Role 可以操作的权限
  • RBAC - RoleBinding

当完成了一个 Namespace 下的角色定义之后,还需要建立其与使用这个角色的主体之间在 Namespace 下的绑定关系,这里需要一个 RoleBinding 模型。使用 RoleBinding 可以将 Role 对应的权限模型绑定到对应的 Subject 上。

在这里插入图片描述

dev-pod-access RoleBinding yaml 文件示例:

apiVerison: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-pod-access
  namespace: test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-access
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: dev

文件解析:

apiVerison: rbac.authorization.k8s.io/v1        表示 RoleBinding 当前所属的组是 rbac.authorization.k8s.io,版本是 v1

kind        表示 Kubernetes 资源类型是 RoleBinding

metadata    表示 RoleBinding 的元数据,元数据通常包含 name、namespace 等

roleRef     表示 RoleBinding 需要绑定的 Role,一个 RoleBinding 只能绑定一个 Role

subjects    表示 RoleBinding 要绑定的对象,可以是 User、Group 或 ServiceAccount。它支持同时绑定多个对象
  • RBAC - ClusterRole

在这里插入图片描述

除了定义指定 Namespace 中的权限模型,也可以通过 ClusterRole 定义一个集群维度的权限模型。在一个 Cluster 实例中,可以定义集群维度的权限使用权限,比如像 PVNodeNamespace 中不可见的资源权限,可以在 ClusterRole 中定义,而操作这些资源的动作同样是之前 Role 中支持的增删改查和 get、list、watch 等操作。

all-pod-access ClusterRole yaml 文件示例:

apiVerison: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: all-pod-access
rules:
- apiGroups: [""]
  resources: ["pods", "pods/attach"]
  verbs: ["get", "list", "watch"]

文件解析:

apiVerison: rbac.authorization.k8s.io/v1        表示 ClusterRole 当前所属的组是 rbac.authorization.k8s.io,版本是 v1

kind        表示 Kubernetes 资源类型是 ClusterRole

metadata    表示 ClusterRole 的元数据,元数据通常包含 name 等

rules       表示 ClusterRole 的规则,apiGroups 表示目标资源的 apiGroups 名称;resources 表示 ClusterRole 可以访问的资源;verbs 表示 Role 可以操作的权限

ClusterRole yaml 文件几乎和 Role 是一模一样的,唯一不同的地方是 ClusterRole 中是所有集群维度的权限定义,不支持 Namespace 的定义。

  • RBAC - ClusterRoleBinding

同样在 ClusterRole 的基础上,可以将其绑定在对应的 Subject 主体上。而 ClusterRoleBinding 可以帮助在集群所有命名空间上将 ClusterRole 绑定到具体的 Subject 对象上。

在这里插入图片描述

dev-all-pod-access ClusterRoleBinding yaml 文件示例:

apiVerison: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dev-all-pod-access
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: all-pod-access
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: dev

文件解析:

apiVerison: rbac.authorization.k8s.io/v1        表示 ClusterRoleBinding 当前所属的组是 rbac.authorization.k8s.io,版本是 v1

kind        表示 Kubernetes 资源类型是 ClusterRoleBinding

metadata    表示 ClusterRoleBinding 的元数据,元数据通常包含 name 等

roleRef     表示 ClusterRoleBinding 需要绑定的 ClusterRole,一个 ClusterRoleBinding 只能绑定一个 ClusterRole

subjects    表示 ClusterRoleBinding 要绑定的对象,可以是 User、Group 或 ServiceAccount。它支持同时绑定多个对象

相比较于 RoleBindingClusterRoleBinding 定义也只是在 NamespaceroleRef 中的权限对象模型定义上有不同,其他的定义格式是一样的。

  • RABC - Default ClusterRoleBinding

在不进行任何权限的绑定下,RABC 会拒绝所有的访问。那么系统组件中是如何请求的呢?

其实在集群创建的时候,处理系统各组件的客户端证书,它们各自的角色和环境对象也会被创建出来,以满足组件业务之间交互必须的权限要求。

在这里插入图片描述

  • verbs 如何设置?

verbs 表示对资源对象具体的操作权限,具体有 get, list, watch, create, patch, delete 等权限。

简单的对照图:

在这里插入图片描述

比如希望在 edit 一个 Deployment 的时候,需要在相应的角色模板中增加对 Deployment 资源的 getpatch 这样的权限。如果希望 exec 到一个 Pod 中,需要在相应的角色模板中增加对 Podget 权限,以及针对 Pod/exec 模型的 create 权限。


Security Context 的使用

  • CVE-2019-5736 漏洞:

在这里插入图片描述

通过对 GitHub 上的统计结果可以看到,主流的业务镜像有 82.4% 是以 root 用户来启动的。通过这个调查可以看到对 Security Context 的相关使用是不容乐观的。

  • Kubernetes runtime 安全策略:

经过对上面的分析结果可以看出来,如果对业务容器配置安全合适的参数,其实攻击者很难有可乘之机。那么究竟应该在部署 Kubernetes 集群中的业务容器做哪些 runtime 的安全加固呢?

在这里插入图片描述

首先要遵循权限最小化原则,除了业务运行所必需的系统权限,其他权限都是可以去除的;

此外可以通过在 Pod 或者 container 维度设置 Security Context 参数,进行业务容器 runtime 的安全配置;

另外可以通过开启 Pod Security Policy,在 Api-Server 请求的 Admission 阶段强制校验容器的安全配置;

除了 Pod Security Policy 的开启之外,如上图还列举了常见的比较多的配置参数。
  • 安全加固总结:

在多租户环境下,如何利用 Kubernetes 下原生的安全能力做安全加固:

RBAC 和 基于 Namespace 的软隔离是基本且必要的安全措施

使用 Pod Security Policy 对 Pod 的安全参数进行校验,同时加固 Pod runtime 安全

使用 Resource Quota & Limit Range 限制租户的资源使用配额

敏感信息保护(secret encryption at REST)

在应用 runtime 遵循权限的最小化原则,尽可能缩小 Pod 内 容器的系统权限

使用 NetworkPolicy 进行业务应用间网络流量的访问控制

Log everything

对接监控系统,实现容器应用维度的监控

猜你喜欢

转载自blog.csdn.net/miss1181248983/article/details/113186996