强化集群的安全性


Kubernetes 的开发速度较快,经常会有新的安全功能供您使用。本页面将指导您完成当前指南中的操作,以加强 Google Kubernetes Engine (GKE) 集群的安全性。

本指南首先介绍重要安全措施,这些措施需要客户在创建集群时执行相关操作。文档较后的部分会提到不太重要的功能、默认安全设置以及可以在创建后启用的功能。如需大致了解安全主题,请阅读安全概览

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

如果以下建议与 CIS GKE 基准建议相关,则本指南会指明这一点。

及时升级 GKE 基础架构

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

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

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

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

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

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

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

CIS GKE 基准建议:6.6.2 - 首选 VPC 原生集群;6.6.3 - 确保启用主授权网络;6.6.4 - 确保在启用专用端点并停用公共访问的情况下创建集群;6.6.5 - 确保使用专用节点创建集群

您应该限制集群控制层面和节点对互联网的公开程度。这些设置只能在创建集群时进行设定。

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

请参阅创建专用集群,了解 GKE 集群控制层面。可以提供网络级保护的专用集群有三种不同的类型:

  • 停用公共端点访问权限:这是最安全的选项,它会阻止对控制层面和节点的所有互联网访问。如果您已将本地网络配置为使用 Cloud InterconnectCloud VPN 连接到 Google Cloud,那么这是一个不错的选择。这些技术会将您的公司网络有效连接到您的云端 VPC。
  • 启用公共端点访问权限,并启用授权网络(推荐):此选项可以限制您定义的来源 IP 地址对控制层面的访问权限。如果您还没有 VPN 基础架构,或者您的远程用户或分支机构通过公共互联网(而不是公司 VPN 和 Cloud Interconnect 或 Cloud VPN)进行连接,这是一个不错的选择。
  • 启用公共端点访问权限,但停用授权网络:这是默认选项,它允许互联网上的任何人与控制层面建立网络连接。

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

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

我们建议集群至少使用授权网络和专用节点。这样可以确保通过以下方式能够访问控制层面:

  • 授权网络中允许的 CIDR。
  • 集群 VPC 中的节点。
  • 管理控制层面的 Google 内部生产作业。

以上方式对应于创建集群时的以下 gcloud 标志:

  • --enable-ip-alias
  • --enable-private-nodes
  • --enable-master-authorized-networks

使用最小权限防火墙规则

通过对防火墙规则使用最小权限原则来最大限度地降低意外访问的风险

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 的首选映像,因为它专门针对正在运行的容器进行了自定义构建、优化和安全强化

启用适用于 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 集群通知接收安全公告,请参阅集群通知

权限

使用最小权限 IAM 服务账号

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

每个 GKE 节点都有一个与其关联的 Identity and Access Management (IAM) 服务账号。默认情况下,系统会为节点提供 Compute Engine 默认服务账号,您可以导航到 Google Cloud 控制台的 IAM 部分找到该账号。默认情况下,此账号具有广泛的访问权限,可用于各种应用,但它的权限超出了运行 Kubernetes Engine 集群的必需权限。您应该创建并使用具有最低权限的服务账号,供节点而不是 Compute Engine 默认服务账号使用。

随着适用于 GKE 的工作负载身份联合的发布,我们建议进一步减少使用节点服务账号。我们希望负责日志记录、监控和类似任务的系统守护程序使用节点服务账号。而 Pod 中的工作负载应通过适用于 GKE 的工作负载身份联合来预配身份。

GKE 要求服务账号至少具有 monitoring.viewermonitoring.metricWriterlogging.logWriterstackdriver.resourceMetadata.writerautoscaling.metricsWriter 角色。详细了解监控角色日志记录角色

以下命令创建的 IAM 服务账号具有操作 GKE 所需的最低权限。您还可以使用服务账号处理其他项目中的资源。如需查看相关说明,请参阅跨项目启用服务账号模拟

gcloud

gcloud iam service-accounts create SA_NAME \
    --display-name=DISPLAY_NAME

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
    --role roles/logging.logWriter

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
    --role roles/monitoring.metricWriter

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
    --role roles/monitoring.viewer

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
    --role roles/stackdriver.resourceMetadata.writer

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com" \
    --role roles/autoscaling.metricsWriter

替换以下内容:

  • SA_NAME:新服务账号的名称。
  • DISPLAY_NAME:新服务账号的显示名称,可使该账号更容易识别。
  • PROJECT_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:新服务账号的显示名称,可使该账号更容易识别。

    然后运行以下命令:

    kubectl apply -f service-account.yaml

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

    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]
    kubectl apply -f policy-logging.yaml

  3. 应用 monitoring.metricWriter 角色。下载以下资源并将其保存为 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]
    kubectl apply -f policy-metrics-writer.yaml

  4. 应用 monitoring.viewer 角色。下载以下资源并将其保存为 policy-monitoring.yaml。将 [SA_NAME][PROJECT_ID] 替换为您自己的信息。

    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]
    kubectl apply -f policy-monitoring.yaml

  5. 应用 autoscaling.metricsWriter 角色。下载以下资源并将其保存为 policy-autoscaling-metrics-writer.yaml。将 [SA_NAME][PROJECT_ID] 替换为您自己的信息。

    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]
    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 中使用私有映像,还需要向以下服务账号授予权限:

gsutil

gsutil iam ch \
  serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com:objectViewer \
  gs://BUCKET_NAME

存储映像的存储桶的名称采用 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 中的注册表)

如需详细了解该命令,请参阅 gsutil iam 文档。

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 用户应考虑以下一项或多项措施:

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

这两个选项都允许从 Cloud Run 和 Cloud Functions 访问 API 服务器 IP 地址。此访问权限将被移除,请勿依赖这些服务与 API 服务器进行通信。如需了解详情,请参阅 Google Cloud 博文

使用命名空间和 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 和 GKE on VMware,因此,如果您在多个环境中运行工作负载,则可以选择这些解决方案。如果您选择使用 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 \
    --no-enable-service-externalips

后续步骤