强化集群的安全性


本页将指导您完成当前最佳实践中的操作,以加强 Google Kubernetes Engine (GKE) 集群的安全性。本指南首先介绍重要安全措施,这些措施需要客户在创建集群时执行相关操作。文档后面会提到不太重要的功能、默认安全设置以及可以在创建后启用的功能。

本文档面向负责定义、管理和实施政策和流程以保护组织数据免遭未经授权的访问的安全专家。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务

在阅读本页面之前,请确保您熟悉以下内容:

如果您要在 GKE 中创建新集群,则默认情况下会启用多项保护措施。如果您要升级现有集群,请务必定期查看本安全强化指南并启用新功能。

默认情况下,在 Autopilot 模式下创建的集群会实现许多 GKE 安全强化功能。

您可以使用 Security Health Analytics 自动检查多项建议以及其他常见的错误配置。

及时升级 GKE 基础架构

CIS GKE 基准建议:6.5.3 - 确保为 GKE 节点启用节点自动升级

要提高安全性,最简单的方法是及时更新 Kubernetes。Kubernetes 经常引入新的安全功能并提供安全补丁。

如需了解安全补丁程序,请参阅 GKE 安全公告

在 Google Kubernetes Engine 中,系统会自动为您修补和升级控制层面。节点自动升级功能还会自动升级集群中的节点。

对于从 2019 年 6 月开始使用Google Cloud 控制台创建的集群,以及从 2019 年 11 月 11 日开始使用 API 创建的集群,系统默认启用节点自动升级。

如果您选择停用节点自动升级,我们建议您按照自己的时间安排每月升级一次。旧版集群应选择启用节点自动升级,并严格按照重要补丁程序的 GKE 安全公告执行相关操作。

如需了解详情,请参阅自动升级节点

限制对控制平面和节点的网络访问

CIS GKE 基准建议:6.6.2 - 首选 VPC 原生集群,6.6.3。确保已启用“已获授权的网络”,6.6.4。确保已创建集群并启用了专用端点和停用了公共访问权限,以及 6.6.5。确保使用专用节点创建集群

默认情况下,GKE 集群控制层面和节点具有互联网可路由地址,这些地址可以从任何 IP 地址进行访问。

最佳实践

限制集群控制平面和节点对互联网的公开程度。

限制对控制平面的访问

如需限制对 GKE 集群控制平面的访问权限,请参阅配置控制平面访问权限。 您可以通过以下方式实现网络级保护:

  • 已启用基于 DNS 的端点(推荐):您可以使用 VPC Service Controls 控制哪些人可以访问基于 DNS 的端点。借助 VPC Service Controls,您可以为项目中的所有 Google API 定义一个安全参数,并为其附加网络来源等情境感知属性。您可以集中控制项目在所有 Google API 中的这些设置,从而减少需要配置访问权限规则的位置。

  • 停用基于 IP 的外部和内部端点访问权限:这会阻止通过基于 IP 的端点访问控制平面。

  • 停用基于 IP 地址的外部端点访问权限:这样可以阻止对两个控制平面的所有互联网访问。如果您已将本地网络配置为使用 Cloud InterconnectCloud VPN 连接到Google Cloud ,那么这是一个不错的选择。这些技术会将您的公司网络有效连接到您的云端 VPC。

  • 启用基于 IP 地址的外部端点访问权限,并启用授权网络:此选项可以限制您定义的来源 IP 地址对控制平面的访问权限。如果您还没有 VPN 基础架构,或者您的远程用户或分支机构通过公共互联网(而不是公司 VPN 和 Cloud Interconnect 或 Cloud VPN)进行连接,这是一个不错的选择。

  • 启用外部端点访问权限,但停用授权网络:这允许互联网上的任何人与控制平面建立网络连接。

如果使用基于 IP 的端点,我们建议集群使用已获授权的网络

这样可以确保通过以下方式能够访问控制平面:

  • 授权网络中允许的 CIDR。
  • 集群 VPC 中的节点。
  • Google 预留的 IP 地址,用于管理集群。

限制对节点的访问

最佳实践

在集群上启用专用节点,以防止外部客户端访问这些节点。

如需停用对节点的直接互联网访问权限,请在创建集群时指定 gcloud CLI 选项 --enable-private-nodes

此选项指示 GKE 使用内部 IP 地址预配节点,这意味着这些节点无法通过公共互联网直接进行访问。

使用最小权限防火墙规则

为防火墙规则使用最小权限原则,最大限度地降低意外访问风险

GKE 会创建默认 VPC 防火墙规则以启用系统功能并实施良好的安全性实践。如需查看自动创建的防火墙规则的完整列表,请参阅自动创建的防火墙规则

GKE 会创建优先级为 1000 的默认防火墙规则。如果您创建具有更高优先级的宽松防火墙规则(例如用于调试的 allow-all 防火墙规则),则集群会面临意外访问风险。

群组身份验证

CIS GKE 基准建议:6.8.3 - 考虑使用 Google RBAC 群组来管理 Kubernetes RBAC 用户

您应该使用群组来管理您的用户。借助群组,您可以通过身份管理系统和身份管理员来控制身份。在群组中添加任何人或从群组中移除任何人时,您只需调整群组成员即可,无需更新 RBAC 配置。

如需使用 Google 群组管理用户权限,您必须在集群上启用 Google RBAC 群组。这样,您可以轻松管理具有相同权限的用户,同时身份管理员也可以集中、一致地管理用户。

如需了解如何启用 Google RBAC 群组,请参阅 Google RBAC 群组

容器节点选项

以下各个部分将介绍安全节点配置选项。

启用安全强化型 GKE 节点

CIS GKE 基准建议:6.5.5 - 确保启用安全强化型 GKE 节点

安全强化型 GKE 节点提供强大、可验证的节点身份和完整性,能够提高 GKE 节点的安全性,应在所有 GKE 集群上启用。

您可以在创建或更新集群时启用安全强化型 GKE 节点。 安全强化型 GKE 节点应启用安全启动功能。如果您需要未签名的第三方内核模块,则不应使用安全启动功能。如需了解如何启用安全强化型 GKE 节点,以及如何安全强化型 GKE 节点如何启用安全启动,请参阅使用安全强化型 GKE 节点

选择具有 containerd 运行时环境的安全强化节点映像

带有 containerd 的 Container-Optimized OS (cos_containerd) 映像是 Container-Optimized OS 映像的变体,其中 containerd 作为与 Kubernetes 直接集成的主容器运行时。

containerd 是 Docker 的核心运行时环境组件,旨在为 Kubernetes 容器运行时环境接口 (CRI) 提供核心容器功能。由于其复杂程度远远低于完整的 Docker 守护程序,因此它具有较小的攻击面。

如需在集群中使用 cos_containerd 映像,请参阅 Containerd 映像

cos_containerd 映像是 GKE 的首选映像,因为它专门针对正在运行的容器进行了自定义构建、优化和安全强化

启用 Workload Identity Federation for GKE

CIS GKE 基准建议:6.2.2 - 优先使用专用 Google Cloud 服务账号和 Workload Identity

建议使用适用于 GKE 的工作负载身份联合向 Google Cloud API 进行身份验证。

适用于 GKE 的工作负载身份联合取代了使用元数据隐藏的需要,因此这两种方法不兼容。由元数据隐藏保护的敏感元数据也受适用于 GKE 的工作负载身份联合保护。

利用 GKE Sandbox 强化工作负载隔离

CIS GKE 基准建议:6.10.4 - 考虑使用 GKE Sandbox 来强化工作负载隔离,尤其是对于不受信任的工作负载

GKE Sandbox 提供了一道额外的安全保障,可防止恶意代码影响集群节点上的主机内核。

您可以在沙盒环境中运行容器,以缓解大多数容器逃逸攻击,也称为本地提权攻击。如需了解过去的容器逃逸漏洞,请参阅安全公告。此类攻击可让攻击者访问容器的主机虚拟机,因此可以访问同一虚拟机上的其他容器。GKE Sandbox 等沙盒有助于限制这些攻击的影响。

在以下情况下,您应该考虑将工作负载放入沙盒:

  • 工作负载运行不受信任的代码
  • 您希望在攻击者破坏工作负载中的容器的情况下限制影响。

请参阅利用 GKE Sandbox 强化工作负载隔离,了解如何使用 GKE Sandbox。

启用安全公告通知

在有与您的集群相关的安全公告时,GKE 会以消息的形式,将这些事件的通知发布到您配置的 Pub/Sub 主题。您可以在 Pub/Sub 订阅上接收这些通知,与第三方服务集成,并且可以过滤要接收的通知类型

如需详细了解如何使用 GKE 集群通知接收安全公告,请参阅集群通知

停用不安全的 kubelet 只读端口

停用 kubelet 只读端口,并将使用端口 10255 的所有工作负载切换为更安全的端口 10250

节点上运行的 kubelet 进程会使用不安全的端口 10255 提供只读 API。Kubernetes 不会对此端口执行任何身份验证或授权检查。kubelet 会在经过身份验证的更安全端口 10250 上提供相同的端点。

如需查看相关说明,请参阅在 GKE 集群中停用 kubelet 只读端口

权限

使用最小权限 IAM 服务账号

CIS GKE 基准建议:6.2.1 - 避免使用 Compute Engine 默认服务账号运行 GKE 集群

GKE 使用附加到节点的 IAM 服务账号来运行日志记录和监控等系统任务。这些节点服务账号至少必须具有项目的 Kubernetes Engine Default Node Service Account (roles/container.defaultNodeServiceAccount) 角色。默认情况下,GKE 会将在项目中自动创建的 Compute Engine 默认服务账号用作节点服务账号。

如果您在项目或组织中将 Compute Engine 默认服务账号用于其他功能,该服务账号可能拥有的权限超出了 GKE 所需的权限,这可能会导致安全风险。

附加到节点的服务账号应仅供执行日志记录和监控等任务的系统工作负载使用。对于您自己的工作负载,请使用 Workload Identity Federation for GKE 预配身份。

如需创建自定义服务账号并向其授予 GKE 所需的角色,请完成以下步骤:

控制台

  1. 在 Google Cloud 控制台中,启用 Cloud Resource Manager API:

    Enable the API

  2. 前往服务账号页面:

    转到“服务账号”

  3. 点击 创建服务账号
  4. 输入服务账号的名称。服务账号 ID 字段会根据名称自动为服务账号生成唯一 ID。
  5. 点击创建并继续
  6. 选择角色菜单中,选择 Kubernetes Engine Default Node Service Account 角色。
  7. 点击完成

gcloud

  1. 启用 Cloud Resource Manager API:
    gcloud services enable cloudresourcemanager.googleapis.com
  2. 创建服务账号:
    gcloud iam service-accounts create SERVICE_ACCOUNT_ID \
        --display-name=DISPLAY_NAME

    替换以下内容:

    • SERVICE_ACCOUNT_ID:服务账号的唯一 ID。
    • DISPLAY_NAME:服务账号的显示名称。
  3. 向服务账号授予 Kubernetes Engine Default Node Service Account (roles/container.defaultNodeServiceAccount) 角色:
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member="serviceAccount:SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
        --role=roles/container.defaultNodeServiceAccount

    替换以下内容:

    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • SERVICE_ACCOUNT_ID:您创建的服务账号 ID。

Config Connector

注意:此步骤需要使用配置连接器。按照安装说明在您的集群上安装配置连接器。

  1. 如需创建服务账号,请下载以下资源并将其保存为 service-account.yaml
    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMServiceAccount
    metadata:
      name: [SA_NAME]
    spec:
      displayName: [DISPLAY_NAME]

    替换以下内容:

    • [SA_NAME]:新服务账号的名称。
    • [DISPLAY_NAME]:服务账号的显示名称。
  2. 创建服务账号:
    kubectl apply -f service-account.yaml
  3. roles/logging.logWriter 角色应用到服务账号:
    1. 下载以下资源并将其保存为 policy-logging.yaml
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-logging
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/logging.logWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      替换以下内容:

      • [SA_NAME] 替换为服务账号的名称。
      • [PROJECT_ID]:您的 Google Cloud 项目 ID。
    2. 将该角色应用于服务账号:
      kubectl apply -f policy-logging.yaml
  4. roles/monitoring.metricWriter 角色应用到服务账号:
    1. 下载以下资源并将其保存为 policy-metrics-writer.yaml。 将 [SA_NAME][PROJECT_ID] 替换为您自己的信息。
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-metrics-writer
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/monitoring.metricWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      替换以下内容:

      • [SA_NAME] 替换为服务账号的名称。
      • [PROJECT_ID]:您的 Google Cloud 项目 ID。
    2. 将该角色应用于服务账号:
      kubectl apply -f policy-metrics-writer.yaml
  5. roles/monitoring.viewer 角色应用到服务账号:
    1. 下载以下资源并将其保存为 policy-monitoring.yaml
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-monitoring
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/monitoring.viewer
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      替换以下内容:

      • [SA_NAME] 替换为服务账号的名称。
      • [PROJECT_ID]:您的 Google Cloud 项目 ID。
    2. 将该角色应用于服务账号:
      kubectl apply -f policy-monitoring.yaml
  6. roles/autoscaling.metricsWriter 角色应用到服务账号:
    1. 下载以下资源并将其保存为 policy-autoscaling-metrics-writer.yaml
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-autoscaling-metrics-writer
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/autoscaling.metricsWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      替换以下内容:

      • [SA_NAME] 替换为服务账号的名称。
      • [PROJECT_ID]:您的 Google Cloud 项目 ID。
    2. 将该角色应用于服务账号:
      kubectl apply -f policy-autoscaling-metrics-writer.yaml

您还可以使用此服务账号处理其他项目中的资源。如需查看相关说明,请参阅跨项目启用服务账号模拟

授予对私有映像库的访问权限

如需在 Artifact Registry 中使用专用映像,请向服务账号授予 Artifact Registry Reader 角色 (roles/artifactregistry.reader)。

gcloud

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --member=serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --role=roles/artifactregistry.reader

REPOSITORY_NAME 替换为您的 Artifact Registry 代码库的名称。

Config Connector

注意:此步骤需要使用配置连接器。按照安装说明在您的集群上安装配置连接器。

  1. 将以下清单保存为 policy-artifact-registry-reader.yaml

    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMPolicyMember
    metadata:
      name: policy-artifact-registry-reader
    spec:
      member: serviceAccount:"SA_NAME"@"PROJECT_ID".iam.gserviceaccount.com
      role: roles/artifactregistry.reader
      resourceRef:
        apiVersion: artifactregistry.cnrm.cloud.google.com/v1beta1
        kind: ArtifactRegistryRepository
        name: "REPOSITORY_NAME"

    替换以下内容:

    • SA_NAME:您的 IAM 服务账号的名称。
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • REPOSITORY_NAME:您的 Artifact Registry 代码库的名称。
  2. 向服务账号授予 Artifact Registry Reader 角色:

    kubectl apply -f policy-artifact-registry-reader.yaml
    

如果您在 Container Registry 中使用私有映像,还需要向以下服务账号授予权限:

gcloud

gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
  --member=serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/storage.objectViewer

存储映像的存储分区的名称采用 BUCKET_NAME 格式:

  • artifacts.PROJECT_ID.appspot.com(适用于推送到主机 gcr.io 中注册表的映像)或
  • STORAGE_REGION.artifacts.PROJECT_ID.appspot.com

替换以下内容:

  • PROJECT_ID:您的 Google Cloud 控制台项目 ID。
  • STORAGE_REGION:存储桶的位置:
    • us(适用于主机 us.gcr.io 中的注册表)
    • eu(适用于主机 eu.gcr.io 中的注册表)
    • asia(适用于主机 asia.gcr.io 中的注册表)

如需详细了解该命令,请参阅 gcloud storage buckets add-iam-policy-binding 文档。

Config Connector

注意:此步骤需要使用配置连接器。按照安装说明在您的集群上安装配置连接器。

storage.objectViewer 角色应用到您的服务账号。下载以下资源并将其保存为 policy-object-viewer.yaml。将 [SA_NAME][PROJECT_ID] 替换为您自己的信息。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-object-viewer
spec:
  member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/storage.objectViewer
  resourceRef:
    kind: Project
    name: [PROJECT_ID]
kubectl apply -f policy-object-viewer.yaml

如果您希望其他真人用户能够使用此服务账号创建新集群或节点池,则必须在此服务账号上向该用户授予 Service Account User 角色:

gcloud

gcloud iam service-accounts add-iam-policy-binding \
    SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --member=user:USER \
    --role=roles/iam.serviceAccountUser

Config Connector

注意:此步骤需要使用配置连接器。按照安装说明在您的集群上安装配置连接器。

iam.serviceAccountUser 角色应用到您的服务账号。下载以下资源并将其保存为 policy-service-account-user.yaml。将 [SA_NAME][PROJECT_ID] 替换为您自己的信息。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-service-account-user
spec:
  member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/iam.serviceAccountUser
  resourceRef:
    kind: Project
    name: [PROJECT_ID]
kubectl apply -f policy-service-account-user.yaml

对于现有的 Standard 集群,您现在可以创建使用新服务账号的新节点池。对于 Autopilot 集群,您必须创建使用该服务账号的新集群。如需查看相关说明,请参阅创建 Autopilot 集群

  • 创建一个使用新服务账号的节点池:

    gcloud container node-pools create NODE_POOL_NAME \
    --service-account=SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --cluster=CLUSTER_NAME

如果您需要 GKE 集群具有其他 Google Cloud服务的访问权限,则应使用适用于 GKE 的工作负载身份联合

限制对集群 API 发现的访问权限

默认情况下,Kubernetes 使用一组宽松的发现 ClusterRoleBinding 引导集群,从而允许广泛访问包括 CustomResourceDefinition 信息在内的集群 API 信息。

用户应注意,system:discoverysystem:basic-user ClusterRoleBinding 的主体中包含的 system:authenticated 群组可以包括任何经过身份验证的用户(包括任何具有 Google 账号的用户),它不代表 GKE 上集群的有意义的安全级别。如需了解详情,请参阅避免使用默认角色和群组

希望强化集群的发现 API 用户应考虑以下一项或多项措施:

  • 仅启用基于 DNS 的端点以访问控制平面。
  • 配置授权网络,将访问仅限于设定的 IP 地址范围。
  • 限制对控制平面的访问并启用专用节点。

如果这些选项都不适合您的 GKE 使用场景,您应该将所有 API 发现信息(即 CustomResources、APIService 定义以及由扩展程序 API 服务器托管的发现信息)视为公开泄露。

使用命名空间和 RBAC 限制对集群资源的访问

CIS GKE 基准建议:5.6.1 - 使用命名空间在各资源之间创建管理边界

通过为每个团队和环境创建单独的命名空间或集群,为团队提供 Kubernetes 所需的最低访问权限。为每个命名空间分配成本中心和适当的标签,以实现责任的明晰化和退款。仅为开发者提供部署和管理应用(特别是在生产环境中)所需的访问权限级别,允许其对命名空间进行访问。制定用户需要对集群执行的任务,并定义他们执行每项任务所需的权限。

如需详细了解如何创建命名空间,请参阅 Kubernetes 文档。 如需了解规划 RBAC 配置的最佳实践,请参阅 GKE RBAC 的最佳实践

IAM基于角色的访问权限控制 (RBAC) 可以协同工作,而实体在任一级层必须具有足够权限,才能使用集群中的资源。

针对 GKE 向群组和用户分配适当的 IAM 角色以提供项目级层的权限,并使用 RBAC 授予集群和命名空间级层的权限。如需了解详情,请参阅访问权限控制

您可以将 IAM 和 RBAC 权限与命名空间结合使用,以限制用户与 Google Cloud 控制台上的集群资源的交互。如需了解详情,请参阅 按命名空间启用访问权限和查看集群资源

使用网络政策限制 Pod 之间的流量

CIS GKE 基准建议:6.6.7 - 确保已启用网络政策,并进行适当设置

默认情况下,集群中的所有 Pod 都可以相互通信。您应该根据工作负载的需要控制 Pod 之间的通信。

限制网络对服务的访问权限可以大大增加攻击者在集群中横向移动的难度,还可以保护服务免遭意外的或故意的拒绝服务攻击。控制流量的两种推荐方法如下:

  1. 使用 Istio。如果您对负载均衡、服务授权、节流、配额、指标等感兴趣,请参阅在 Google Kubernetes Engine 上安装 Istio
  2. 使用 Kubernetes 网络政策。请参阅创建集群网络政策。如果您需要 Kubernetes 所提供的基本访问权限控制功能,请选择此方法。如需实现使用网络政策限制流量的常用方法,请遵循 GKE Enterprise 安全蓝图中的实现指南。此外,Kubernetes 文档还很好地演示了简单的 nginx 部署。考虑使用网络政策日志记录来验证您的网络政策是否按预期工作。

如果需要,可以同时使用 Istio 和网络政策。

密钥管理

CIS GKE 基准建议:6.3.1 - 考虑使用 Cloud KMS 中托管的密钥来加密 Kubernetes Secret

您应该为存储在 etcd 中的敏感数据(例如 Secret)提供额外保护。如需执行此操作,您需要配置与 GKE 集群集成的 Secret 管理器。某些解决方案可以同时用于 GKE 和 Google Distributed Cloud,因此,如果您在多个环境中运行工作负载,则可以选择这些解决方案。如果您选择使用 HashiCorp Vault 之类的外部 Secret 管理器,则需要在创建集群之前先设置该管理器。

您可以通过多种方式来管理 Secret。

  • 您可以在 GKE 本地使用 Kubernetes Secret。或者,您可以通过应用层 Secret 加密,使用您管理的密钥在应用层对这些 Secret 进行加密。
  • 您可以使用 HashiCorp Vault 等 Secret 管理器。在安全加固的 HA 模式下运行时,此管理器会提供一种可用于生产用途的一致方法来管理 Secret。您可以使用 Kubernetes 服务账号或 Google Cloud 服务账号向 HashiCorp Vault 进行身份验证。如需详细了解如何将 GKE 与 Vault 搭配使用,请参阅在 Kubernetes 上运行和连接到 HashiCorp Vault

GKE 虚拟机默认在存储层加密,其中包括 etcd。

使用准入控制器强制执行政策

准入控制器是负责管理和实施集群使用方式的插件。您必须启用它们才能使用 Kubernetes 的一些更高级的安全功能;它们是强化集群的深度防御方法的重要组成部分。

默认情况下,Kubernetes 中的 Pod 可以使用必需功能之外的功能。您应该将 Pod 的功能限制在工作负载必需的范围内。

Kubernetes 支持众多控制机制,用于限制 Pod,使其仅使用明确授予的功能来执行任务。例如,Policy Controller 适用于舰队中的集群。Kubernetes 还具有内置的 PodSecurity 准入控制器,该控制器让您可在单个集群中强制执行 Pod 安全标准。

Policy Controller 是 GKE Enterprise 的一项功能,可让您使用声明式政策大规模在 GKE 集群上强制执行和验证安全性。如需了解如何使用 Policy Controller 在 GKE 集群上强制执行声明式控制,请参阅安装 Policy Controller

借助 PodSecurity 准入控制器,您可以在特定命名空间或整个集群中实施预定义的政策。这些政策对应于不同的 Pod 安全标准

限制工作负载自行修改的能力

某些 Kubernetes 工作负载(尤其是系统工作负载)有权执行自行修改。例如,某些工作负载会自行纵向自动扩缩。虽然很方便,但这会使得已入侵节点的攻击者能够在集群中进行进一步的操作。例如,攻击者可能会使节点上的工作负载自行更改,以将其作为在同一命名空间内具有更高权限的服务账号运行。

理想情况下,不应最初便为工作负载授予自行修改的权限。如果需要自行修改,您可以通过应用 Gatekeeper 或 Policy Controller 限制条件来限制权限,例如可以使用开源 Gatekeeper 库中提供的 NoUpdateServiceAccount(该库提供了许多有用的安全政策)。

部署政策时,通常需要允许管理集群生命周期的控制器绕过政策。这样控制器才能更改集群,例如应用集群升级。例如,如果您在 GKE 上部署 NoUpdateServiceAccount 政策,则必须在 Constraint 中设置以下参数:

parameters:
  allowedGroups:
  - system:masters
  allowedUsers:
  - system:addon-manager

限制已弃用的 gcePersistentDisk 卷类型的使用

已弃用的 gcePersistentDisk 卷类型允许您将 Compute Engine 永久性磁盘装载到 Pod。我们建议您在工作负载中限制 gcePersistentDisk 卷类型的使用。虽然 Google Cloud 在将磁盘挂接到底层虚拟机时执行授权检查,但 GKE 在装载此卷类型时不会对 Pod 执行任何 IAM 授权检查。因此,已经能够在命名空间中创建 Pod 的攻击者可以访问 Google Cloud 项目中的 Compute Engine 永久性磁盘内容。

如需访问和使用 Compute Engine 永久性磁盘,请改用 PersistentVolume 和 PersistentVolumeClaim。在集群中应用安全政策,以阻止使用 gcePersistentDisk 卷类型。

为了防止使用 gcePersistentDisk 卷类型,请在 PodSecurity 准入控制器中应用基准或受限政策,或者您可以在 Policy Controller 或 Gatekeeper 准入控制器中定义自定义限制条件。

如需定义自定义限制条件来限制此卷类型,请执行以下操作:

  1. 安装基于政策的准入控制器,例如 Policy Controller 或 Gatekeeper OPA。

    Policy Controller

    在集群中安装 Policy Controller

    Policy Controller 是面向 GKE 用户的付费功能。 Policy Controller 基于开源 Gatekeeper,但您也可以访问完整的限制条件模板库、政策包以及与 Google Cloud 控制台信息中心集成,以帮助观察和维护集群。政策包是可应用于集群的专业最佳实践,其中包括基于 CIS Kubernetes 基准等建议的包。

    Gatekeeper

    在集群中安装 Gatekeeper

    对于 Autopilot 集群,请在文本编辑器中打开 Gatekeeper gatekeeper.yaml 清单。修改 MutatingWebhookConfiguration 规范中的 rules 字段,以将通配符 (*) 字符替换为特定的 API 组和资源名称,如以下示例所示:

    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    ...
    webhooks:
    - admissionReviewVersions:
      - v1
      - v1beta1
      ...
      rules:
      - apiGroups:
        - core
        - batch
        - apps
        apiVersions:
        - '*'
        operations:
        - CREATE
        - UPDATE
        resources:
        - Pod
        - Deployment
        - Job
        - Volume
        - Container
        - StatefulSet
        - StorageClass
        - Secret
        - ConfigMap
      sideEffects: None
      timeoutSeconds: 1
    

    将更新后的 gatekeeper.yaml 清单应用于 Autopilot 集群,以安装 Gatekeeper。这是必需操作,因为作为内置的安全措施,Autopilot 不允许在变更准入 webhook 中使用通配符字符。

  2. 部署内置 Pod 安全政策卷类型 ConstraintTemplate:

    kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/volumes/template.yaml
    
  3. 将包含允许的卷类型列表的以下限制条件保存为 constraint.yaml

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: k8sPSPVolumeTypes
    metadata:
      name: nogcepersistentdisk
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pods"]
      parameters:
        volumes: ["configMap", "csi", "projected", "secret", "downwardAPI", "persistentVolumeClaim", "emptyDir", "nfs", "hostPath"]
    

    此限制条件会将卷限制为 spec.parameters.volumes 字段中的列表。

  4. 部署限制条件:

    kubectl apply -f constraint.yaml
    

监控集群配置

您应该审核集群配置与您定义的设置之间是否存在差异。

您可以使用 Security Health Analytics 自动检查本安全强化指南中介绍的多项建议以及其他常见的错误配置。

安全默认设置

以下各个部分介绍了新集群中默认的安全配置选项。您应验证先前存在的集群采用了安全配置。

保护节点元数据

CIS GKE 基准建议:6.4.1 - 确保停用旧版 Compute Engine 实例元数据 API;6.4.2 - 确保启用 GKE 元数据服务器

v0.1v1beta1 Compute Engine 元数据服务器端点已被弃用,并已于 2020 年 9 月 30 日关停。这些端点不会强制执行元数据查询标头。如需了解关停时间表,请参阅 v0.1v1beta1 元数据服务器端点弃用

针对 Kubernetes 的一些实际攻击需要通过访问虚拟机的元数据服务器来提取凭据。如果您使用适用于 GKE 的工作负载身份联合元数据隐藏,则这些攻击会被阻止。

停用旧的客户端身份验证方法

CIS GKE 基准建议:6.8.1 - 确保停用“使用静态密码进行基本身份验证”;6.8.2 - 确保停用“使用客户端证书进行身份验证”

向 Kubernetes API 服务器进行身份验证的方法有多种。在 GKE 中,受支持的方法包括服务账号不记名令牌、OAuth 令牌和 x509 客户端证书。GKE 通过 gcloud 管理身份验证,让您能够使用 OAuth 令牌方法,设置 Kubernetes 配置,获取访问令牌并使其保持最新。

在 GKE 与 OAuth 集成之前,一次性生成的 x509 证书或静态密码是唯一可用的身份验证方法,但现在不推荐使用且应停用。这些方法具有更大的危害集群安全的攻击面,从 GKE 1.12 版开始已默认处于停用状态。如果您使用的是旧版身份验证方法,我们建议您将其停用。静态密码身份验证已弃用,并且自 GKE 1.19 版起已移除。

现有集群应移动到 OAuth。如果集群外部的系统需要使用长期凭据,我们建议您创建具有所需权限的 Google 服务账号或 Kubernetes 服务账号并导出密钥。

如需更新现有集群并移除静态密码,请参阅停用静态密码身份验证

目前,无法从现有集群中移除以前颁发的客户端证书,但如果启用了 RBAC 且停用了 ABAC,则该证书将失去权限。

启用 Cloud Logging

CIS GKE 基准建议:6.7.1 - 确保已启用 Stackdriver Kubernetes Logging 和 Monitoring

为了减少运营开销并维护日志的统一视图,请在部署集群的任何位置实施一致的日志记录策略。GKE Enterprise 集群默认与 Cloud Logging 集成,应保持这种配置。

默认情况下,所有 GKE 集群都会启用 Kubernetes 审核日志记录功能,该功能会按时间顺序记录对 Kubernetes API 服务器进行的调用。Kubernetes 审核日志条目适合用于调查可疑 API 请求、收集统计信息,或针对不当 API 调用创建监控提醒。

GKE 集群将 Kubernetes Audit Logging 与 Cloud Audit LogsCloud Logging 集成。您可以将日志从 Cloud Logging 路由到自己的日志记录系统。

停用 Kubernetes 网页界面(信息中心)

CIS GKE 基准建议:6.10.1 - 确保已停用 Kubernetes 网页界面

在 GKE 上运行时,不应启用 Kubernetes 网页界面(信息中心)。

Kubernetes 网页界面(信息中心)由具有较高权限的 Kubernetes 服务账号提供支持。由于 Google Cloud 控制台提供了很多相同功能,因此您无需这些权限。

如需停用 Kubernetes 网页界面,请运行以下命令:

gcloud container clusters update CLUSTER_NAME \
    --update-addons=KubernetesDashboard=DISABLED

停用 ABAC

CIS GKE 基准建议:6.8.4 - 确保已停用旧版授权 (ABAC)

您应该停用基于属性的访问权限控制 (ABAC),转而在 GKE 中使用基于角色的访问权限控制 (RBAC)。

默认情况下,对于使用 GKE 1.8 及更高版本创建的集群,ABAC 处于停用状态。在 Kubernetes 中,RBAC 用于在集群级层和命名空间级层授予对资源的权限。借助 RBAC,您可以使用包含一组权限的规则来定义角色。与 ABAC 相比,RBAC 具有明显的安全优势。

如果您仍需使用 ABAC,请先查看使用 RBAC 的前提条件。如果您从旧版本升级集群并且使用的是 ABAC,则应该更新访问权限控制配置:

gcloud container clusters update CLUSTER_NAME \
    --no-enable-legacy-authorization

如需按照上述建议创建新集群,请运行以下命令:

gcloud container clusters create CLUSTER_NAME \
    --no-enable-legacy-authorization

DenyServiceExternalIPs 准入控制器保持启用状态

请勿停用 DenyServiceExternalIPs 准入控制器。

DenyServiceExternalIPs 准入控制器会阻止 Service 使用 ExternalIP,并缓解已知安全漏洞

在基于 GKE 1.21 版及更高版本创建的新集群上,DenyServiceExternalIPs 准入控制器默认处于启用状态。对于升级到 GKE 1.21 及更高版本的集群,您可以使用以下命令启用准入控制器:

gcloud beta container clusters update CLUSTER_NAME \
    --location=LOCATION \
    --no-enable-service-externalips

后续步骤