强化集群的安全性

本文档介绍如何强化 GKE on Bare Metal 集群的安全性。

使用 SELinux 保护您的容器

您可以启用 Red Hat Enterprise Linux (RHEL) 和 CentOS 支持的 SELinux 来保护您的容器。如果您的宿主机正在运行 RHEL 或 CentOS,并且您想要为集群启用 SELinux,则您必须在所有宿主机上启用 SELinux。如需了解详情,请参阅使用 SELinux 保护容器

使用 seccomp 限制容器

安全计算模式 (seccomp) 在 GKE on Bare Metal 版本 1.11 中提供。使用 seccomp 配置文件运行容器可提高集群的安全性,因为它限制了允许容器对内核进行的系统调用。这样可以降低内核漏洞被利用的可能性。

默认的 seccomp 配置文件包含容器可以进行的系统调用列表。不允许列表中的任何系统调用。在 GKE on Bare Metal 1.11 版中,seccomp 默认处于启用状态。这意味着所有系统容器和客户工作负载都使用容器运行时的默认 seccomp 配置文件运行。即使是未在配置文件中指定 seccomp 配置文件的容器和工作负载也受 seccomp 限制的约束。

如何在整个集群或特定工作负载上停用 seccomp

您只能在集群创建或集群升级期间停用 seccompbmctl update 不能用于停用此功能。如果要在集群内停用 seccomp,请将以下 clusterSecurity 部分添加到集群的配置文件中:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: example
  namespace: cluster-example
spec:
...
  clusterSecurity:
    enableSeccomp: false
...

万一您的某些工作负载需要执行 seccomp 默认阻止的系统调用,您不必对整个集群停用 seccomp。您可以改为选择在 unconfined mode 中运行的特定工作负载。在 unconfined mode 中运行工作负载有助于释放工作负载,使其不受 seccomp 配置文件对集群其余部分的限制。

如需在 unconfined mode 中运行容器,请将以下 securityContext 部分添加到 Pod 清单:


apiVersion: v1
kind: Pod
....
spec:
  securityContext:
    seccompProfile:
      type: Unconfined
....

不要以 root 用户身份运行容器

默认情况下,容器中的进程以 root 身份执行。这会带来潜在的安全问题,因为如果某个进程脱离容器,该进程将在宿主机上以 root 身份运行。因此,建议以非根用户身份运行所有工作负载。

以下部分介绍了以非根用户身份运行容器的两种方式。

方法 1:在 Dockerfile 中添加 USER 指令

此方法使用 Dockerfile 来确保容器不会以 root 用户身份运行。在 Dockerfile 中,您可以指定容器中的进程应以哪个用户的身份运行。Dockerfile 的以下代码段展示了如何执行此操作:

....

#Add a user with userid 8877 and name nonroot
RUN useradd −u 8877 nonroot

#Run Container as nonroot
USER nonroot
....

在本示例中,Linux 命令 useradd -u 会在容器内创建一个名为 nonroot 的用户。此用户的用户 ID (UID) 为 8877

Dockerfile 中的下一行运行 USER nonroot 命令。此命令指定从映像的时间点开始,命令以用户 nonroot 的身份运行。

向 UID 8877 授予权限,以便容器进程可以为 nonroot 正确执行。

方法 2:在 Kubernetes 清单文件中添加 securityContext 字段

此方法使用 Kubernetes 清单文件来确保容器不会以 root 用户身份运行。系统会为 Pod 指定安全设置,并且这些安全设置会反过来应用于 Pod 中的所有容器。

以下示例展示了给定 Pod 的清单文件摘录:


apiVersion: v1
kind: Pod
metadata:
  name: name-of-pod
spec:
  securityContext:
    runAsUser: 8877
    runAsGroup: 8877
....

runAsUser 字段指定对于 Pod 中的任何容器,所有进程均使用用户 ID 8877 运行。runAsGroup 字段指定这些进程具有主要组 ID (GID) 8877。请记得向 UID 8877 授予必要且足够的权限,以便容器进程能够正常执行。

这可确保容器内的进程以 UID 8877 的身份运行,该 UID 比根用户具有更少的特权。

GKE on Bare Metal 中的系统容器可帮助安装和管理集群。这些容器使用的 UID 和 GID 可由集群规范中的字段 startUIDRangeRootlessContainers 控制。startUIDRangeRootlessContainers 是可选字段,如果未指定,则值为 2000。允许的 startUIDRangeRootlessContainers 值为 1000–57000。startUIDRangeRootlessContainers 值只能在升级期间更改。系统容器将使用 startUIDRangeRootlessContainersstartUIDRangeRootlessContainers + 2999 范围内的 UID 和 GID。

以下示例展示了集群的清单文件摘录:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: name-of-cluster
spec:
 clusterSecurity:
    startUIDRangeRootlessContainers: 5000
...

选择 startUIDRangeRootlessContainers 的值时,应使系统容器使用的 UID 和 GID 空间与分配给用户工作负载的 UID 和 GID 空间不重叠。

如何停用无根模式

从 GKE on Bare Metal 版本 1.10 开始,Kubernetes 控制平面容器和系统容器默认以非根用户的身份运行。GKE on Bare Metal 为这些用户分配 2000-4999 范围内的 UID 和 GID。但是,如果这些 UID 和 GID 已分配给环境中运行的进程,则此分配可能会造成问题。

从 GKE on Bare Metal 版本 1.11 开始,您可以在升级集群时停用无根模式。停用无根模式后,Kubernetes 控制平面容器和系统容器会以根用户身份运行。

如需停用无根模式,请执行以下步骤:

  1. 将以下 clusterSecurity 部分添加到集群的配置文件中:

    apiVersion: baremetal.cluster.gke.io/v1
    kind: Cluster
    metadata:
      name: example
      namespace: cluster-example
    spec:
    ...
      clusterSecurity:
        enableRootlessContainers: false
    ...
    
  2. 升级集群。如需了解详情,请参阅升级集群

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

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

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

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

parameters:
  allowedGroups:
  - system:masters
  allowedUsers: []

停用 kubelet 只读端口

从 1.15.0 版开始,GKE on Bare Metal 默认停用 kubelet 只读端口 10255。您应将所有配置为从这个不安全的 kubelet 端口 10255 读取数据的客户工作负载迁移到使用安全的 kubelet 端口 10250。

只有使用 1.15.0 或更高版本创建的集群才会默认停用此端口。对于使用低于 1.15.0 的版本创建的集群,kubelet 只读端口 10255 仍可访问,即使在集群升级到 1.15.0 版或更高版本后也是如此。

进行此更改的原因是 kubelet 会通过未经身份验证的端口 10255 泄露低敏感度信息,包括在节点上运行的所有 Pod 的完整配置信息,这些信息可能被攻击者利用。它还会泄露指标和状态信息,这些信息可以提供业务敏感的数据洞见。

CIS Kubernetes 基准建议停用 kubelet 只读端口。如需在版本 1.14 中手动停用端口,请参阅停用 kubelet 只读端口

维护

监控安全公告并升级集群是集群启动并运行后要实施的重要安全措施。

监控安全公告

GKE Enterprise 安全团队会针对严重程度为“高”和“严重”的漏洞发布安全公告

这些公告遵循常见的 Google Cloud 漏洞编号方案,并且链接到 Google Cloud 主公告页面和 GKE on Bare Metal 版本说明。使用此 XML Feed 订阅 GKE on Bare Metal 及相关产品的安全公告:https://cloud.google.com/feeds/anthos-gke-security-bulletins.xml 订阅

如果需要客户操作才能解决这些严重程度为高和严重的漏洞,Google 会通过电子邮件与客户联系。此外,Google 可能还会通过支持渠道就支持合同事宜联系客户。

如需详细了解 Google 如何管理 GKE 和 GKE Enterprise 的安全漏洞和补丁,请参阅安全修补

升级集群

Kubernetes 经常引入新的安全功能并提供安全补丁程序。GKE on Bare Metal 版本包含 Kubernetes 安全增强功能,可解决可能会影响集群的安全漏洞。

您负责确保 GKE 集群保持最新状态。对于每个版本,请查看版本说明。为了最大限度地降低 GKE 集群的安全风险,请计划每月更新到新的补丁版本,每三个月更新到次要版本。

升级集群的许多优势之一是自动刷新集群的 kubeconfig 文件。kubeconfig 文件会向集群验证用户身份。使用 bmctl 创建集群时,kubeconfig 文件会添加到集群目录。默认名称和路径为 bmctl-workspace/CLUSTER_NAME/CLUSTER_NAME-kubeconfig。在升级集群时,集群的 kubeconfig 文件会自动续订。否则,kubeconfig 文件会在创建一年后过期。

如需了解如何升级集群,请参阅升级集群