首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
Kubernetes IP Masquerade Agent 用户指南
Kubernetes云管理控制器
Kubernetes安全地清空一个节点
Kubernetes保护集群
Kubernetes调试DNS问题
Kubernetes改变默认 StorageClass
Kubernetes更改PersistentVolume的回收策略
Kubernetes关键插件Pod的调度保证
Kubernetes静态加密Secret数据
Kubernetes开发云控制器管理器
Kubernetes控制节点上的CPU管理策略
Kubernetes控制节点上的拓扑管理策略
Kubernetes名字空间演练
Kubernetes配置API对象配额
启用/禁用 Kubernetes API
Kubernetes迁移多副本的控制面
Kubernetes升级集群
Kubernetes声明网络策略
Kubernetes使用CoreDNS进行服务发现
Kubernetes使用KMS驱动进行数据加密
使用Kubernetes API访问集群
Kubernetes使用NUMA感知的内存管理器
Kubernetes通过名字空间共享集群
Kubernetes通过配置文件设置Kubelet参数
为Kubernetes运行etcd集群
Kubernetes为节点发布扩展资源
Kubernetes限制存储使用量
Kubernetes验证已签名容器镜像
以非root用户身份运行Kubernetes节点组件
在Kubernetes集群中使用NodeLocal DNSCache
在Kubernetes集群中使用sysctl
Kubernetes在集群中使用级联删除
在运行中的集群上重新配置节点的 kubelet
Kubernetes自定义DNS服务
Kubernetes自动扩缩集群DNS服务
当前位置:
首页>>
技术小册>>
Kubernetes中文教程(五)
小册名称:Kubernetes中文教程(五)
本文展示如何启用和配置静态 Secret 数据的加密。 * 需要 etcd v3.0 或者更高版本 * 要加密自定义资源,你的集群必须运行 Kubernetes v1.26 或更高版本。 * 在 Kubernetes v1.27 或更高版本中可以使用通配符配置资源加密。 ## 配置并确定是否已启用静态数据加密 `kube-apiserver` 的参数 `--encryption-provider-config` 控制 API 数据在 etcd 中的加密方式。 该配置作为一个名为 [`EncryptionConfiguration`] 的 API 提供。 `--encryption-provider-config-automatic-reload` 布尔参数决定了磁盘内容发生变化时是否应自动重新加载 `--encryption-provider-config` 设置的文件。这样可以在不重启 API 服务器的情况下进行密钥轮换。 下面提供了一个示例配置。 **重要:** 对于高可用配置(有两个或多个控制平面节点),加密配置文件必须相同! 否则,`kube-apiserver` 组件无法解密存储在 etcd 中的数据。 ## 理解静态数据加密 ```yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets - configmaps - pandas.awesome.bears.example providers: - identity: {} - aesgcm: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - aescbc: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - secretbox: keys: - name: key1 secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - resources: - events providers: - identity: {} # 即使如下指定 *.* 也不会加密 events - resources: - '*.apps' providers: - aescbc: keys: - name: key2 secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg== - resources: - '*.*' providers: - aescbc: keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` 每个 `resources` 数组项目是一个单独的完整的配置。 `resources.resources` 字段是应加密的 Kubernetes 资源(例如 Secret、ConfigMap 或其他资源)名称 (`resource` 或 `resource.group`)的数组。 如果自定义资源被添加到 `EncryptionConfiguration` 并且集群版本为 1.26 或更高版本, 则 `EncryptionConfiguration` 中提到的任何新创建的自定义资源都将被加密。 在该版本之前存在于 etcd 中的任何自定义资源和配置不会被加密,直到它们被下一次写入到存储为止。 这与内置资源的行为相同。请参阅[确保所有 Secret 都已加密]一节。 `providers` 数组是可能的加密 provider 的有序列表,用于你所列出的 API。 每个条目只能指定一个 provider 类型(可以是 `identity` 或 `aescbc`,但不能在同一个项目中同时指定二者)。 列表中的第一个 provider 用于加密写入存储的资源。 当从存储器读取资源时,与存储的数据匹配的所有 provider 将按顺序尝试解密数据。 如果由于格式或密钥不匹配而导致没有 provider 能够读取存储的数据,则会返回一个错误,以防止客户端访问该资源。 `EncryptionConfiguration` 支持使用通配符指定应加密的资源。 使用 “`*.<group>`” 加密 group 内的所有资源(例如以上例子中的 “`*.apps`”)或使用 “`*.*`” 加密所有资源。“`*.`” 可用于加密核心组中的所有资源。“`*.*`” 将加密所有资源,甚至包括 API 服务器启动之后添加的自定义资源。 不允许在同一资源列表或跨多个条目中使用相互重疊的通配符,因为这样一来配置的一部分将无法生效。 `resources` 列表的处理顺序和优先级由配置中列出的顺序决定。 如果启用了通配符,但想要针对特定资源退出加密,则可以通过添加带有资源名称的新 `resources` 数组项, 后跟附带 `identity` 提供商的 `providers` 数组项。例如,如果启用了 “`*.*`”, 但想要排除对 `events` 资源的加密,则应向 `resources` 数组添加一个新项(以 `events` 为资源名称), 后跟包含 `identity` 的 providers 数组。新项应如下所示: ```yaml - resources: - events providers: - identity: {} ``` 确保新项列在资源数组中的通配符 “`*.*`” 项之前,使新项优先。 有关 `EncryptionConfiguration` 结构体的更多详细信息, 请参阅[加密配置 API]。 如果通过加密配置无法读取资源(因为密钥已更改),唯一的方法是直接从底层 etcd 中删除该密钥。 任何尝试读取资源的调用将会失败,直到它被删除或提供有效的解密密钥。 ### Providers 名称 | 加密类型 | 强度 | 速度 | 密钥长度 | 其它事项 -----|------------|----------|-------|------------|--------------------- `identity` | 无 | N/A | N/A | N/A | 不加密写入的资源。当设置为第一个 provider 时,资源将在新值写入时被解密。 `secretbox` | XSalsa20 和 Poly1305 | 强 | 更快 | 32 字节 | 较新的标准,在需要高度评审的环境中可能不被接受。 `aesgcm` | 带有随机数的 AES-GCM | 必须每 200k 写入一次 | 最快 | 16、24 或者 32字节 | 建议不要使用,除非实施了自动密钥循环方案。 `aescbc` | 填充 [PKCS#7] 的 AES-CBC | 弱 | 快 | 32 字节 | 由于 CBC 容易受到密文填塞攻击(Padding Oracle Attack),不推荐使用。 `kms v1` | 使用信封加密方案:数据使用带有 [PKCS#7] 填充的 AES-CBC(v1.25 之前),从 v1.25 开始使用 AES-GCM 通过数据加密密钥(DEK)加密,DEK 根据 Key Management Service(KMS)中的配置通过密钥加密密钥(Key Encryption Keys,KEK)加密 | 最强 | 快 | 32 字节 | 建议使用第三方工具进行密钥管理。为每个加密生成新的 DEK,并由用户控制 KEK 轮换来简化密钥轮换。从 `v1.27` 开始,该功能处于 Beta 阶段。系统在启动时生成一个新的 DEK 并重复使用它进行加密。当 KEK 被轮转时,DEK 也会被轮转。[配置 KMS V2 provider]。 每个 provider 都支持多个密钥 - 在解密时会按顺序使用密钥,如果是第一个 provider,则第一个密钥用于加密。 在 EncryptionConfig 中保存原始的加密密钥与不加密相比只会略微地提升安全级别。 请使用 `kms` 驱动以获得更强的安全性。 默认情况下,`identity` 驱动被用来对 etcd 中的 Secret 数据提供保护,而这个驱动不提供加密能力。 `EncryptionConfiguration` 的引入是为了能够使用本地管理的密钥来在本地加密 Secret 数据。 使用本地管理的密钥来加密 Secret 数据能够保护数据免受 etcd 破坏的影响,不过无法针对主机被侵入提供防护。 这是因为加密的密钥保存在主机上的 EncryptionConfig YAML 文件中, 有经验的入侵者仍能访问该文件并从中提取出加密密钥。 封套加密(Envelope Encryption)引入了对独立密钥的依赖,而这个密钥并不保存在 Kubernetes 中。 在这种情况下,入侵者需要攻破 etcd、kube-apiserver 和第三方的 KMS 驱动才能获得明文数据,因而这种方案提供了比本地保存加密密钥更高的安全级别。 ## 加密你的数据 创建一个新的加密配置文件: ```yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets - configmaps - pandas.awesome.bears.example providers: - aescbc: keys: - name: key1 secret: <BASE 64 ENCODED SECRET> - identity: {} ``` 遵循如下步骤来创建一个新的 Secret: 1. 生成一个 32 字节的随机密钥并进行 base64 编码。如果你在 Linux 或 macOS 上,请运行以下命令: ```shell head -c 32 /dev/urandom | base64 ``` 2. 将这个值放入到 `EncryptionConfiguration` 结构体的 `secret` 字段中。 3. 设置 `kube-apiserver` 的 `--encryption-provider-config` 参数,将其指向配置文件所在位置。 你将需要把新的加密配置文件挂载到 `kube-apiserver` 静态 Pod。以下是这个操作的示例: 1. 将新的加密配置文件保存到控制平面节点上的 `/etc/kubernetes/enc/enc.yaml`。 2. 编辑 `kube-apiserver` 静态 Pod 的清单:`/etc/kubernetes/manifests/kube-apiserver.yaml`, 代码范例如下: ```yaml apiVersion: v1 kind: Pod metadata: annotations: kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.10.30.4:6443 creationTimestamp: null labels: component: kube-apiserver tier: control-plane name: kube-apiserver namespace: kube-system spec: containers: - command: - kube-apiserver ... - --encryption-provider-config=/etc/kubernetes/enc/enc.yaml # <-- 增加这一行 volumeMounts: ... - name: enc # <-- 增加这一行 mountPath: /etc/kubernetes/enc # <-- 增加这一行 readonly: true # <-- 增加这一行 ... volumes: ... - name: enc # <-- 增加这一行 hostPath: # <-- 增加这一行 path: /etc/kubernetes/enc # <-- 增加这一行 type: DirectoryOrCreate # <-- 增加这一行 ... ``` 4. 重启你的 API 服务器。 你的配置文件包含可以解密 etcd 内容的密钥,因此你必须正确限制控制平面节点的访问权限, 以便只有能运行 `kube-apiserver` 的用户才能读取它。 ## 验证数据已被加密 数据在写入 etcd 时会被加密。重新启动你的 `kube-apiserver` 后,任何新创建或更新的 Secret 或在 `EncryptionConfiguration` 中配置的其他资源类型都应在存储时被加密。 如果想要检查,你可以使用 `etcdctl` 命令行程序来检索你的 Secret 数据内容。 1. 创建一个新的 secret,名称为 `secret1`,命名空间为 `default`: ```shell kubectl create secret generic secret1 -n default --from-literal=mykey=mydata ``` 2. 使用 `etcdctl` 命令行,从 etcd 中读取 Secret: ``` ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C ``` 这里的 `[...]` 是用来连接 etcd 服务的额外参数。 例如: ```shell ETCDCTL_API=3 etcdctl \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ get /registry/secrets/default/secret1 | hexdump -C ``` 输出类似于(有删减): ```hexdump 00000000 2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74 |/registry/secret| 00000010 73 2f 64 65 66 61 75 6c 74 2f 73 65 63 72 65 74 |s/default/secret| 00000020 31 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |1.k8s:enc:aescbc| 00000030 3a 76 31 3a 6b 65 79 31 3a c7 6c e7 d3 09 bc 06 |:v1:key1:.l.....| 00000040 25 51 91 e4 e0 6c e5 b1 4d 7a 8b 3d b9 c2 7c 6e |%Q...l..Mz.=..|n| 00000050 b4 79 df 05 28 ae 0d 8e 5f 35 13 2c c0 18 99 3e |.y..(..._5.,...>| [...] 00000110 23 3a 0d fc 28 ca 48 2d 6b 2d 46 cc 72 0b 70 4c |#:..(.H-k-F.r.pL| 00000120 a5 fc 35 43 12 4e 60 ef bf 6f fe cf df 0b ad 1f |..5C.N`..o......| 00000130 82 c4 88 53 02 da 3e 66 ff 0a |...S..>f..| 0000013a ``` 3. 验证存储的密钥前缀是否为 `k8s:enc:aescbc:v1:`,这表明 `aescbc` provider 已加密结果数据。 确认 `etcd` 中显示的密钥名称和上述 `EncryptionConfiguration` 中指定的密钥名称一致。 在此例中,你可以看到在 `etcd` 和 `EncryptionConfiguration` 中使用了名为 `key1` 的加密密钥。 4. 通过 API 检索,验证 Secret 是否被正确解密: ```shell kubectl get secret secret1 -n default -o yaml ``` 其输出应该包含 `mykey: bXlkYXRh`,`mydata` 的内容是被加密过的, 请参阅[解密 Secret] 了解如何完全解码 Secret 内容。 ## 确保所有 Secret 都被加密 由于 Secret 是在写入时被加密,因此对 Secret 执行更新也会加密该内容。 ```shell kubectl get secrets --all-namespaces -o json | kubectl replace -f - ``` 上面的命令读取所有 Secret,然后使用服务端加密来更新其内容。 如果由于冲突写入而发生错误,请重试该命令。 对于较大的集群,你可能希望通过命名空间或更新脚本来对 Secret 进行划分。 ## 轮换解密密钥 在不发生停机的情况下更改 Secret 需要多步操作,特别是在有多个 `kube-apiserver` 进程正在运行的高可用环境中。 1. 生成一个新密钥并将其添加为所有服务器上当前 provider 的第二个密钥条目 1. 重新启动所有 `kube-apiserver` 进程以确保每台服务器都可以使用新密钥进行解密 1. 将新密钥设置为 `keys` 数组中的第一个条目,以便在配置中使用其进行加密 1. 重新启动所有 `kube-apiserver` 进程以确保每个服务器现在都使用新密钥进行加密 1. 运行 `kubectl get secrets --all-namespaces -o json | kubectl replace -f -` 以用新密钥加密所有现有的 Secret 1. 在使用新密钥备份 etcd 后,从配置中删除旧的解密密钥并更新所有密钥 当只运行一个 `kube-apiserver` 实例时,第 2 步可以忽略。 ## 解密所有数据 要禁用静态加密,请将 `identity` provider 作为配置中的第一个条目并重新启动所有 `kube-apiserver` 进程。 ```yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - identity: {} - aescbc: keys: - name: key1 secret: <BASE 64 ENCODED SECRET> ``` 然后运行以下命令以强制解密所有 Secret: ```shell kubectl get secrets --all-namespaces -o json | kubectl replace -f - ``` ## 进一步学习 [EncryptionConfiguration 配置 API ]。
上一篇:
Kubernetes关键插件Pod的调度保证
下一篇:
Kubernetes开发云控制器管理器
该分类下的相关小册推荐:
Kubernets合辑13-集群监控
Kubernetes合辑1-安装Kubernetes
Kubernets合辑3-kubernetes介绍
Kubernetes中文教程(一)
Kubernets合辑6-服务发现
Kubernets合辑11-持续集成
Kubernetes中文教程(四)
Kubernets合辑8-权限控制
Kubernets合辑9-资源约束
Kubernets合辑7-存储
Kubernets合辑4-kubernetes入门
Kubernetes中文教程(三)