etcd 加密

在 中安装并运维 etcd Encryption Manager,以自动执行集群内的 etcd 数据加密密钥轮换。

它可确保存储在 etcd 中的敏感数据(例如 secrets 和 configmaps)使用安全算法进行加密,从而增强集群安全性。

密钥策略

该插件支持两种密钥策略。请选择与您的集群角色匹配的策略。

策略适用场景密钥生成方式
random适用于独立运行的 workload 和 DCS 集群的默认策略(无 etcd 同步)。每次轮换都会在本地生成一个新的随机密钥。
deterministic必需用于 global 集群,尤其是通过 etcd Synchronizer 在 DR 方案中配对部署时。每个密钥都基于共享的 root Secret 和共享的 SeedBundle 确定性派生,因此 Active 和 Standby 集群对同一 revision 始终获得相同的密钥。

在 deterministic 模式下,运行时的 Active / Standby 角色会自动检测;这不是手动安装参数。

安装

该插件根据目标集群支持两种安装路径:

有关通用插件安装流程,请参见 Cluster Plugin。

Workload / DCS 集群(random 策略)

  • 支持的集群类型:On-Premises、DCS。
  • 无需额外安装参数——通过标准 Cluster Plugin 工作流安装即可。

Global 集群(Deterministic 模式)

DR 配对要求

对于 Global DR 配对,必须在 deterministic 模式下同时在 Active 和 Standby 集群上安装插件,并在两侧配置完全相同的 replication_group_id 和 root_secret_name(以及匹配的 root key 材料)。如果配置不对称或不匹配,Standby 将派生出与 Active 不同的按 revision 密钥,从而破坏故障切换。

前提条件

  • 集群必须是 global 集群。当 global.cluster.name 为 global 时,插件会强制设置 etcdEncryption.keyStrategy=deterministic;对于标记为 is-global=true 的集群,插件配置 UI 也会将该字段默认设置为 deterministic。
etcd Synchronizer 版本

在以 deterministic 模式安装 etcd Encryption Manager 之前,必须先安装版本 v4.3.7 或更高 的 etcd Synchronizer 插件。较早版本不会复制共享的 SeedBundle,因此 Standby 集群无法派生匹配的密钥。

插件参数

插件表单会暴露以下用于 deterministic 安装的参数。

插件参数是否必需默认值目的
key_strategy是random; 对于 global 集群会动态默认为 deterministic。在每次轮换随机生成密钥与确定性派生密钥之间进行选择。
replication_group_id是插件 UI 会预填当前集群名称(不推荐——见下文)。标识 Active / Standby DR 组,并参与 HKDF 域分离。
root_secret_name是etcd-derivation-rootkube-system 中保存 deterministic root key 材料的 Secret 名称。

rootSecretRef.namespace 固定为 kube-system,不会在表单中暴露。

key_strategy
值含义
random单集群随机轮换。
deterministic基于共享的 root Secret 和 SeedBundle 派生密钥。

对于 global 集群,这必须是 deterministic。

replication_group_id
属性值
目的标识一个 Active / Standby DR 复制组,并参与 HKDF 域分离。
一致性要求同一 DR 组中的 Active 和 Standby 集群必须使用完全相同的值。
UI 中的默认值当前集群名称。
是否建议保留默认值否。

建议:

  • 对于使用 etcd Synchronizer 构建的 DR 集群,同一 DR 组的两侧必须共享相同的 replication_group_id。
  • 为避免泄露真实业务、环境或集群身份,即使 UI 已预填集群名称,也不要复用它。请在安装前规划一个单独的、无业务含义的标识符。
  • UUID 风格的标识符可能比较适合,例如 6f1b9e2c-7c3a-4a9c-8b72-2fd0f8f3c1ab。

要从命令行生成 UUID 风格的值:

uuidgen
在两个集群上使用相同的值

先生成一次该值,然后在 DR 组的 Active 和 Standby 集群上配置相同的 replication_group_id。在两侧生成不同的值会产生不同的加密密钥。

root_secret_name
属性值
目的指向 deterministic root key Secret。
默认值etcd-derivation-root
固定命名空间kube-system
跨集群要求同一 replication group 中的所有集群必须使用相同的 root key 材料。

插件表单只暴露 Secret 名称;命名空间在渲染时始终为 kube-system。

准备 Root Secret

在安装插件之前,deterministic root Secret 必须已存在于 kube-system 中。请分两步准备:

  1. 生成 32 字节的密码学强随机材料到 ./root-key.bin。这些字节必须来自高熵源——通常是操作系统的 CSPRNG。openssl rand 是一个安全的默认选择;同样基于 OS CSPRNG 的等效命令也可以使用,例如 head -c 32 /dev/urandom > ./root-key.bin。不要使用 shell 的 $RANDOM、语言级别的 rand(),或任何基于时间种子的生成器。

    openssl rand -out ./root-key.bin 32
  2. 使用该文件在 kube-system 中创建 Secret:

    kubectl -n kube-system create secret generic etcd-derivation-root \
      --from-file=root-key=./root-key.bin

如果您使用不同的 Secret 名称,请将上面的 etcd-derivation-root 替换为您将填写到 root_secret_name 的值。

在两个集群上使用相同的密钥材料

先生成一次 ./root-key.bin,然后将同一个文件传输到复制组中的每个集群,并在每个集群上执行 kubectl create secret 步骤。不要为每个集群重新生成密钥材料——不同的 root key 字节会产生不同的加密密钥。

高级配置(chart values,插件表单未暴露)

显示高级 chart 值

以下字段存在于 chart 中,但不会作为插件安装参数暴露。除非您通过 YAML / Helm 覆盖安装,否则它们将保留 chart 默认值。

Chart 字段默认值目的
etcdEncryption.deterministic.activationPolicytimed-approval控制新派生密钥何时生效。对于 Global 集群请设置为 manual — 请参见 审批 deterministic 密钥轮换。
etcdEncryption.deterministic.approvalDelay30m在 timed-approval 下应用的延迟。仅当 activationPolicy 为 timed-approval 时相关。
etcdEncryption.deterministic.derivationAlgorithmhkdf-sha512-v1用于从 root Secret 派生按 revision 密钥的算法。
etcdEncryption.deterministic.dimensiondefault额外的 HKDF 域分隔符。除非您有意拆分密钥谱系,否则请保持默认值。
etcdEncryption.deterministic.rootSecretRef.namespacekube-system固定值;不会在表单中暴露。
Global 集群请将 activationPolicy 设置为 manual

对于 Global Active/Standby 配对,请显式将 activationPolicy 设置为 manual。在 operator 确认 Standby 集群上对应的 revision 已准备就绪之前,Active 集群上的新密钥 revision 不得生效。如果省略 activationPolicy,插件默认会使用带 30m 延迟的 timed-approval——有关其风险,请参见 Timed Approval。


工作原理

安装后,会在 kube-system 命名空间中部署一个 etcd-encryption-manager 控制器,它会:

  • 定期轮换 etcd 数据加密密钥。
  • 保留最近 8 个密钥,以便回滚兼容。
  • 更新所有控制节点上的加密配置。
  • 触发 kube-apiserver 热加载新密钥。
  • 自动迁移资源,以使用新密钥重新加密数据。

在这些操作期间,集群稳定性会得到保持。

当插件以 deterministic 模式安装在 global DR 配对上时,控制器还会:

  • 在运行时自动检测自己处于 Active 还是 Standby——这不是手动配置。
  • 在 Active 侧生成 SeedBundle,并让 etcd Synchronizer 将其复制到 Standby。
  • 在 Standby 侧,从共享的 SeedBundle 和 root Secret 派生相同的按 revision 密钥,因此在发生故障切换时无需手动复制密钥即可获得相同的加密密钥。

默认配置

参数值
加密资源secrets、configmaps
加密算法256 位 AES-GCM
轮换间隔168 小时(7 天)

运维指南

配置文件

路径内容
/etc/kubernetes/encryption-provider.conf当前加密配置
/etc/kubernetes/encryption-provider-history.bak历史密钥记录(用于恢复)
/etc/kubernetes/encryption-provider-bak/已过期的加密配置版本

检查状态

运行以下命令检查当前轮换状态:

kubectl get EtcdEncryptionConfig default -o yaml

示例输出:

apiVersion: cluster.alauda.io/v1alpha1
kind: EtcdEncryptionConfig
metadata:
  name: default
spec:
  resources:
    - secrets
    - configmaps
  rotationInterval: 168h0m0s
  type: aesgcm
status:
  deployStatus:
    192.168.100.1:
      revision: 3
      state: Success
    192.168.100.2:
      revision: 3
      state: Success
    192.168.100.3:
      revision: 3
      state: Success
  migration:
    completeTimestamp: "2025-05-27T05:47:01Z"
    resources:
      - secrets
      - configmaps
    revision: 3
    state: Success
  revision: 3

审批 deterministic 密钥轮换

当 encryption manager 在 deterministic 模式下轮换密钥时,新 revision 会在 Active 集群上进入 WaitingApproval 阶段。在 operator 审批之前,该密钥不会生效。设置此门控的原因在于:Active 集群不得使用 Standby 还未加载的密钥来加密数据——否则一旦发生故障切换,Standby 将无法解密新的密文。

审批始终只在 Active 集群 上执行。不要补丁修改 Standby's EtcdKeySeedBundleState,也不要直接编辑任何资源的 status 字段。

手动审批(推荐)

步骤 1 — 识别待处理 revision。

登录到 Active 集群的一个 control-plane 节点,并列出所有 bundle 状态:

kubectl get eksbs \
  -o custom-columns='NAME:.metadata.name,REVISION:.spec.revision,PHASE:.status.phase,APPROVED:.spec.approved'

找到 PHASE=WaitingApproval 且 APPROVED=false 的行。记录其 revision 编号:

REVISION=<revision-number>
STATE="seed-bundle-state-${REVISION}"
BUNDLE="seed-bundle-${REVISION}"

步骤 2 — 验证 Standby 就绪状态。

登录到 Standby 集群的一个 control-plane 节点,并检查相同的 revision:

kubectl get eksbs "$STATE" \
  -o custom-columns='REVISION:.spec.revision,PHASE:.status.phase,PREPARED_AT:.status.preparedAt'

输出必须显示目标 revision 的 PHASE=Prepared。如果对象缺失、仍处于 Preparing,或为 Failed,请停止——继续之前先调查 etcd Synchronizer 路径。

步骤 3 — 交叉检查派生输入。

在 Active 和 Standby 集群 上运行以下命令并比较输出。replicationGroupID、dimension 和 derivationAlgorithm 必须完全一致:

kubectl get eksb "$BUNDLE" \
  -o custom-columns='REVISION:.spec.revision,GROUP:.spec.replicationGroupID,DIMENSION:.spec.dimension,ALGORITHM:.spec.derivationAlgorithm'

步骤 4 — 审批。

在 Active 集群上,审批待处理 revision:

kubectl patch eksbs "$STATE" \
  --type=merge -p '{"spec":{"approved":true}}'

该 patch 会记录审批。此后,激活、部署到 control-plane 节点以及数据迁移将异步进行。

步骤 5 — 确认激活完成。

在 Active 集群上,检查 bundle 状态和迁移进度:

kubectl get eksbs "$STATE" \
  -o custom-columns='REVISION:.spec.revision,PHASE:.status.phase,MESSAGE:.status.message'
kubectl get eec default \
  -o custom-columns='REVISION:.status.revision,MIGRATION_STATE:.status.migration.state,MIGRATION_REVISION:.status.migration.revision'

当满足以下条件时,轮换完成:

  • bundle 状态达到 PHASE=Active。
  • eec/default 显示新的 REVISION 且 MIGRATION_STATE=Success。

要检查 Active 集群上按节点的部署进度:

kubectl get eec default \
  -o go-template='{{range $node, $status := .status.deployStatus}}{{printf "%s\t%s\t%d\t%s\n" $node $status.state $status.revision $status.message}}{{end}}'

每个 control-plane 节点都必须对新 revision 报告 state=Success。如果 bundle 仍然处于 Activating,则表示部署或迁移仍在进行中(或在失败后重试)。

定时审批(不推荐)

定时审批在故障切换期间存在数据丢失风险

对于 Global Active/Standby 配对,不推荐使用 timed-approval。approvalDelay 计时器(默认 30m)是 Active 集群上的本地倒计时——它不会检查 Standby 是否实际上已加载新密钥。如果 etcd 同步缓慢、Standby 网络分区,或者 Standby control plane 正在维护中,截止时间可能会在 Standby 仍未准备好时到期。在这个窗口内发生故障切换会导致 Standby 无法解密使用新密钥加密的数据。

当 activationPolicy 设置为 timed-approval 时,控制器会在创建 EtcdKeySeedBundleState 后、approvalDelay 到期时自动审批待处理 revision。该延迟必须足够长,以便整个 Standby 准备流水线完成:

阶段发生的事情典型耗时
Syncetcd Synchronizer 将 SeedBundle 复制到 Standby秒级(取决于跨地域延迟)
ReconcileStandby 控制器派生密钥并更新本地 EncryptionConfig秒级
DeployDeployer 将新的 provider 配置写入所有 Standby control-plane 节点秒到分钟级(随节点数量扩展)
ReloadStandby kube-apiserver 加载新的 provider秒到分钟级(取决于 encryption provider 配置是否启用了自动重载)

默认的 30m 为具有小型 control plane 的典型单地域部署提供了缓冲。如果您的环境包含跨地域复制、大型 control plane,或未启用自动 provider 重载的集群,请增大该值。

必需监控

如果您选择 timed-approval,在启用该策略之前,必须确认 Active 和 Standby 集群上的监控与告警均已正常工作。

encryption manager 会暴露以下 Prometheus 指标:

指标
指标类型描述
etcd_encryption_manager_bundle_waiting_approval_secondsGauge当前 bundle 处于 WaitingApproval 的时长(秒)。按 activation_policy(manual 或 timed-approval)打标签。
etcd_encryption_manager_timed_approval_remaining_secondsGauge距离定时审批截止时间剩余的秒数。负值表示截止时间已过。仅当 timed-approval bundle 处于 WaitingApproval 时发出。
etcd_encryption_manager_bundle_activatingGauge当任意 bundle 当前处于 Activating 阶段时为 1。
etcd_encryption_manager_bundle_activation_failedGauge当 Activating bundle 出现显式部署或迁移失败时为 1。
内置告警规则

该插件包含以下告警:

告警严重级别条件
EtcdEncryptionManagerApprovalRequiredwarningmanual bundle 已在 WaitingApproval 中持续 ≥ 5 分钟。
EtcdEncryptionManagerApprovalOverduecriticalmanual bundle 已在 WaitingApproval 中持续 ≥ 30 分钟。
EtcdEncryptionManagerTimedApprovalDeadlineApproachingwarningtimed-approval bundle 在自动审批前剩余 ≤ 10 分钟。
EtcdEncryptionManagerTimedApprovalDeadlinePassedcriticaltimed-approval bundle 的截止时间已过,但仍处于 WaitingApproval。
EtcdEncryptionManagerActivationFailedcriticalActivating bundle 出现部署或迁移失败。
EtcdEncryptionManagerActivationStuckcritical某个 bundle 已处于 Activating 状态 ≥ 30 分钟。

这些告警会在各个集群上独立触发。对于 Global 集群,应该重点处理的是 Active 集群上的 EtcdEncryptionManagerTimedApprovalDeadlineApproaching 关键告警——它会给您 10 分钟窗口来检查 Standby 是否已处于 Prepared,如果没有,则切换为 manual。

跨集群关联

每个集群都独立运行自己的指标和告警。内置告警检测的是本地问题——例如 Active 上卡住的 WaitingApproval,或者 Standby 上失败的激活。要将两者关联起来(例如“Active 即将自动审批,但 Standby هنوز未 Prepared”),请将两个集群的指标汇总到一个中心 Prometheus / Thanos / Victoria Metrics 实例中。

应急响应

如果 EtcdEncryptionManagerTimedApprovalDeadlineApproaching 告警触发且 Standby 尚未就绪,请将 Active 切换为 manual 以停止自动审批。在 Active 集群上:

kubectl patch eec default \
  --type=merge -p '{"spec":{"deterministic":{"activationPolicy":"manual"}}}'

验证当前待处理 bundle 已切换:

kubectl get eksbs \
  -o custom-columns='NAME:.metadata.name,REVISION:.spec.revision,PHASE:.status.phase,APPROVED:.spec.approved'

该 bundle 仍必须显示 APPROVED=false。之后再切回 timed-approval 只会影响未来的 bundle——当前 bundle 仍受手动控制。如果该 bundle 已经进入 Activating,则说明截止时间已经生效;请按照上面的 激活检查 执行,不要假设更改策略会将其回滚。