第九章:K8s安全机制:认证、授权与准入控制

随着Kubernetes成为云原生应用的事实标准,保障其安全性变得至关重要。一个配置不当的集群,如同一个门户大开的金库,不仅可能导致应用数据泄露,攻击者甚至可以利用其计算资源进行恶意活动,或者将其作为攻击内网其他系统的跳板。

Kubernetes的安全性是一个多层次的、纵深防御的体系。从物理基础设施到应用代码,每一层都需要被保护。本章将重点聚焦于集群本身的安全,特别是所有与集群交互的入口——Kubernetes API Server的安全机制。

对API Server的每一次请求,无论是来自kubectl命令,还是来自集群内部的某个Pod,都必须依次通过三道严格的安全关卡,才能被最终执行:

  1. 认证 (Authentication):验证请求者的身份,回答“你是谁?”。
  2. 授权 (Authorization):检查该身份是否有权限执行请求的操作,回答“你被允许做什么?”。
  3. 准入控制 (Admission Control):在请求被持久化到etcd之前,进行最后的审查、修改或拒绝,回答“这个请求是否合规?”。

理解这“三驾马车”的工作原理,是安全地设计、管理和运维Kubernetes集群的先决条件。

9.1 K8s安全概述:4C安全模型

为了更宏观地理解Kubernetes安全,社区提出了4C安全模型,它将云原生安全划分为四个层次,由内到外分别是:Code(代码)、Container(容器)、Cluster(集群)、Cloud/Corporate Data Center(云/企业数据中心)

  • Cloud / Corporate Data Center (云/企业数据中心层):这是最底层的基础设施安全。包括物理服务器的安全、数据中心的网络隔离、云服务商提供的身份认证(IAM)、虚拟网络(VPC)等。这一层的安全是后面所有层次的基石。
  • Cluster (集群层):这是本章的重点。它关注的是Kubernetes集群自身的安全,主要分为两大块:
    • 保护控制平面组件:确保API Server、etcd、Controller Manager、Scheduler之间的通信是加密和受信任的;严格限制对etcd的直接访问。
    • 保护工作节点组件:确保Kubelet的安全,配置网络策略(Network Policies)来隔离Pod之间的网络流量。
  • Container (容器层):关注容器镜像和运行时的安全。包括:
    • 镜像安全:对容器镜像进行漏洞扫描,使用最小化的基础镜像,不使用来源不明的镜像。
    • 运行时安全:遵循最小权限原则,禁止容器以root用户身份运行,使用安全上下文(Security Context)限制容器的能力,利用AppArmor、Seccomp等内核安全模块。
  • Code (代码层):关注在容器内运行的应用程序本身的安全。包括安全的编码实践、处理好依赖库的漏洞、安全的API设计、加密处理敏感数据等。

这个模型的核心思想是**“层层设防,纵深防御”**。上一层的安全依赖于下一层的安全。即使某一层被攻破,其他层仍然可以作为防线,减缓或阻止攻击的蔓延。

9.2 认证(Authentication):确认“你是谁”

认证是API安全流程的第一步。当一个请求到达API Server时,API Server必须先确定请求者的身份。Kubernetes中有两种基本的用户类型:

  1. 普通用户 (Normal Users)

    • 这类用户被认为是由外部、独立的服务管理的。例如,公司的LDAP、企业级的身份提供商(IdP)如Google、Okta,或者由管理员分发的客户端证书。
    • Kubernetes本身没有用于表示普通用户的API对象。你无法通过kubectl create user这样的命令来创建一个用户。
  2. 服务账户 (ServiceAccounts)

    • 这类“用户”是由Kubernetes API管理的,专门供在Pod中运行的进程使用,以便它们可以与API Server进行通信。
    • ServiceAccount是命名空间级别的资源。每个命名空间在创建时都会自动创建一个名为default的ServiceAccount。
    • 当Pod被创建时,如果没有指定ServiceAccount,它会自动使用所在命名空间的default ServiceAccount。
    • Kubernetes会自动为ServiceAccount创建一个对应的Secret(在较新版本中是临时的Token),并将其以Token的形式挂载到Pod的 /var/run/secrets/kubernetes.io/serviceaccount/目录下,供Pod内的应用使用。
Kubernetes的认证策略

API Server可以同时启用一种或多种认证策略。它会按顺序逐一尝试,只要有一个策略成功认证了请求,认证阶段就通过了。常见的认证策略包括:

  • X.509客户端证书:这是最常见的认证方式,尤其用于集群管理员和控制平面组件之间的通信。API Server通过启动时配置的CA证书来验证客户端证书的有效性。证书的Common Name (CN)字段被用作用户名Organization (O)字段被用作该用户所属的用户组
  • 静态Token文件:管理员可以创建一个包含token,user,uid,"group1,group2"格式的CSV文件,API Server启动时加载此文件。请求者在HTTP头的Authorization字段中提供Bearer <token>即可。这种方式简单但不灵活,修改后需要重启API Server。
  • ServiceAccount Tokens:这是专门为ServiceAccount设计的认证方式。它使用签名的JWT (JSON Web Token)。Pod内的应用读取挂载的token文件,并将其包含在发往API Server的请求头中。API Server会验证这个JWT的签名和有效性。
  • OpenID Connect (OIDC) Tokens:这是将Kubernetes与外部身份提供商(如Google, Auth0, Dex)集成的标准和推荐方式。用户首先在IdP上进行认证,获取一个ID Token,然后使用kubectl时将此Token提供给API Server。API Server会与IdP通信以验证Token的有效性。这种方式使得企业可以利用现有的身份认证体系来统一管理K8s集群的用户。

9.3 授权(Authorization):判定“你能做什么”

一旦用户的身份被成功认证,授权模块就会介入,决定这个已认证的用户是否有权限执行其请求的操作。例如,用户dev-user(已认证)想要get podsproduction命名空间中,授权模块会检查dev-user是否被授予了这样的权限。

与认证类似,API Server也可以配置多种授权模式,但目前社区的绝对标准和最佳实践是RBAC

  • RBAC (Role-Based Access Control):基于角色的访问控制。这是本章的重中之重。它通过将权限(Permissions)聚合到角色(Roles)中,再将角色绑定(Binding)到用户、用户组或ServiceAccount上,来实现精细化、可重用的权限管理。
【重难点】理解并掌握RBAC是保障集群安全的核心

RBAC通过四个核心的API对象来实现其强大的权限管理能力:Role、ClusterRole、RoleBinding、ClusterRoleBinding

RBAC的四个构建基块:

  1. Role (角色)

    • 作用域命名空间级别 (Namespaced)
    • 内容:包含了一组规则(rules),每条规则定义了一组可以对某些API资源执行的操作(verbs)。
    • 简单来说:一个Role就是一份在特定命名空间内的权限清单。
    # pod-reader-role.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default # 这个Role只在default命名空间内有效
      name: pod-reader
    rules:
    - apiGroups: [""] # "" 表示核心API组
      resources: ["pods"]
      verbs: ["get", "watch", "list"] # 允许对Pod进行读操作
    
  2. ClusterRole (集群角色)

    • 作用域集群级别 (Cluster-scoped)
    • 内容:与Role一样,也包含一组权限规则。
    • 用途
      1. 授予对集群级别的资源(如nodes, persistentvolumes, clusterroles等)的访问权限。
      2. 授予对所有命名空间中的命名空间级别资源(如pods)的访问权限。
    • 简单来说:一份在整个集群范围内都有效的权限清单。
    # secret-reader-clusterrole.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      # ClusterRole不需要namespace
      name: secret-reader
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    
  3. RoleBinding (角色绑定)

    • 作用域命名空间级别
    • 作用:将一个Role授予一个或多个主体(subjects)(用户、用户组或ServiceAccount)。
    • 关键点RoleBinding只能引用在同一命名空间内Role
    • 简单来说:在某个命名空间里,“把某张权限清单(Role)交给某个人(Subject)”。
    # bind-pod-reader-role.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-pods
      namespace: default # 绑定行为发生在default命名空间
    subjects:
    - kind: User
      name: jane # 'jane'这个用户
      apiGroup: rbac.authorization.k8s.io
    roleRef: # 引用要绑定的Role
      kind: Role
      name: pod-reader # 引用上面创建的pod-reader Role
      apiGroup: rbac.authorization.k8s.io
    

    执行这个绑定后,用户jane就获得了在default命名空间中读取Pod的权限。

  4. ClusterRoleBinding (集群角色绑定)

    • 作用域集群级别
    • 作用:将一个ClusterRole授予一个或多个主体。
    • 关键点ClusterRoleBinding授予的权限在所有命名空间以及集群级别都有效。
    • 简单来说:在整个集群范围内,“把某张集群级权限清单(ClusterRole)交给某个人(Subject)”。
    # bind-secret-reader-clusterrole.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: read-secrets-global
    subjects:
    - kind: Group
      name: managers # 'managers'这个用户组
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: secret-reader # 引用上面创建的secret-reader ClusterRole
      apiGroup: rbac.authorization.k8s.io
    

    执行这个绑定后,managers用户组中的所有成员都获得了在集群所有命名空间中读取Secret的权限。这是一个非常高的权限,需要谨慎授予。

RBAC最佳实践与核心原则:

  • 遵循最小权限原则:这是RBAC的黄金法则。永远只授予主体完成其任务所必需的最小权限。不要为了方便而授予cluster-admin权限。
  • 优先使用Role和RoleBinding:对于应用级的ServiceAccount,它们的活动范围通常只限定在自己的命名空间内。因此,应优先使用RoleRoleBinding来限制其权限。只有在需要管理集群级资源或跨命名空间资源时,才考虑使用ClusterRole
  • 为应用创建专用的ServiceAccount:不要使用default ServiceAccount。为每个应用创建一个专用的ServiceAccount,并为其绑定一个精心设计的、权限最小化的Role
  • 避免使用通配符:在定义规则时,尽量避免在resourcesverbs中使用通配符["*"]。明确列出所需的资源和操作。
  • 定期审计:定期审查集群中的(Cluster)RoleBinding,检查是否存在权限过高或不再需要的主体,及时清理。

9.4 准入控制(Admission Control):API请求的最后一道防线

在请求通过认证和授权之后,但在被持久化到etcd之前,它会经过一个由准入控制器(Admission Controllers)组成的链条。准入控制器是一系列插件,它们可以对请求进行校验(Validating)变更(Mutating)

  • 变更型准入控制器 (Mutating Admission Controllers):可以修改请求的对象。例如,自动为Pod注入一个Sidecar容器,或者为一个没有设置资源请求的Pod添加默认值。
  • 校验型准入控制器 (Validating Admission Controllers):只能检查请求的对象,不能修改。如果检查不通过,就可以拒绝该请求。例如,强制要求所有Pod都必须设置资源限制(Limits)。

API Server会按预先定义的顺序依次调用这些控制器。如果链条中的任何一个控制器拒绝了请求,那么整个API请求都会失败。

一些重要的内置准入控制器:

  • NamespaceLifecycle: 防止在一个正在被删除的命名空间中创建新的对象。
  • LimitRanger: 强制执行在LimitRange对象中定义的资源约束。
  • ResourceQuota: 强制执行在ResourceQuota对象中定义的资源配额。
  • DefaultStorageClass: 为没有指定storageClassNamePersistentVolumeClaim自动添加默认的存储类。

动态准入控制:Webhook

除了内置的控制器,Kubernetes还允许你通过Webhook来集成自定义的、外部的准入控制逻辑。

  • MutatingAdmissionWebhook: API Server会将请求对象发送给你自己部署的一个Web服务。你的服务可以修改这个对象,然后将其返回给API Server。
  • ValidatingAdmissionWebhook: API Server将请求对象发送给你的Web服务,你的服务只需返回一个允许或拒绝的决定。

Webhook极大地扩展了Kubernetes的能力,使其可以集成各种企业级的安全策略和治理流程。例如:

  • 校验策略
    • 强制所有容器镜像必须来自公司信任的镜像仓库。
    • 禁止创建hostPath类型的Volume。
    • 要求所有Ingress对象的主机名必须以.my-company.com结尾。
  • 变更策略
    • 为所有Pod自动添加公司标准的标签(labels)和注解(annotations)。
    • 自动注入用于日志收集或服务网格的Sidecar容器。

**OPA (Open Policy Agent)**是一个非常流行的开源项目,它经常与ValidatingAdmissionWebhook结合使用,以一种声明式的方式(使用Rego语言)来编写和强制执行复杂的安全策略。

总结:安全三部曲的协同工作

阶段 核心问题 实现机制 例子
1. 认证 “你是谁?” 客户端证书, ServiceAccount Token, OIDC Token… API Server验证了请求来自用户jane
2. 授权 (RBAC) “你能做什么?” Role, ClusterRole, RoleBinding, ClusterRoleBinding… 检查发现jane通过一个RoleBinding被授予了在dev命名空间delete pods的权限。
3. 准入控制 “这个请求合规吗?” LimitRanger, ResourceQuota, Webhooks… 一个Validating Webhook检查发现这个Pod使用了latest标签的镜像,根据公司策略,这不被允许,于是拒绝了该请求。

只有当一个API请求成功闯过这三道关卡,它才会被最终写入etcd,并触发后续的控制器逻辑。掌握这一流程,并能够熟练运用RBAC和准-入控制来实施最小权限原则和自定义安全策略,是成为一名合格的Kubernetes管理员或安全工程师的必备技能。

K8s 详细学习笔记 目录

以下是整个系列的10章目录,点击章节标题即可跳转阅读:

更多推荐