TT Lab
开始
学习 学习路径 课程

CKS — Kubernetes 安全专家

Secret 的处理与静态加密

在 TT Lab 中继续学习

目标

按类型创建 Secret,确认不同注入方式会产生怎样的暴露路径,使用 RBAC 收窄读取范围,并亲自编写静态加密配置文件。

为什么重要

Secret 清单中的值采用 base64,看起来仿佛经过加密,但 base64 只是编码,不是加密。它没有密钥,只需一条命令即可还原。在默认配置下,Secret 以明文保存在 etcd 中,因此任何取得 etcd 备份文件的人都能读取所有 Secret。只有启用 EncryptionConfiguration 后,存储的值才会真正加密;此时 identity Provider 必须位于列表最后。如果它在前面,就会退回明文存储。

注入方式也很重要。环境变量可通过 /proc/PID/environ 读取,会被子进程继承,还可能完整出现在崩溃报告或调试页面中。卷挂载更加安全,通常还会使用 defaultMode 收紧文件权限。

最后是 RBAC。在某个命名空间拥有 get secrets 权限的人,可以读取该命名空间中的所有 Secret。可以通过 resourceNames 只允许访问特定 Secret,这一点出乎意料地鲜为人知。

步骤

  1. 创建命名空间 cks-secrets,并在其中创建 Opaque Secret db-cred。 包含两个键:username(值为 app)和 password(值为 pr0d-Db-Pass)。
  2. 在 cks-secrets 中创建类型为 kubernetes.io/dockerconfigjson 的 Secret registry-cred。 服务器为 registry.cks.local,用户名为 ci,密码为 ci-token。
  3. 在 cks-secrets 中创建类型为 kubernetes.io/tls 的 Secret shop-tls。tls.crt 和 tls.key 均不得为空。
  4. 在 cks-secrets 中创建 Pod env-app(容器名称 app,镜像 nginx:1.27-alpine)。 容器的 envFrom[0].secretRef.name 为 db-cred。
  5. 在 cks-secrets 中创建 Pod vol-app(容器名称 app)。卷名称为 db, secret.secretName 为 db-cred,secret.defaultMode 为 0400(十进制 256), 容器将该卷挂载到 /etc/db,并设置 readOnly: true。
  6. 在 cks-secrets 中创建 Opaque Secret app-config。唯一的键为 mode(值为 strict), immutable 为 true。
  7. 在 cks-secrets 中创建 ServiceAccount app 和 Role db-cred-reader。 apiGroups 为核心组,resources 为 secrets,resourceNames 仅为 db-cred, verbs 仅为 get。通过 RoleBinding app-db-cred 绑定给 SA app。 然后按顺序将两个问题的答案(yes/no)分两行保存到 /root/cks-secrets/can-i.txt。第一行:SA app 能否 get secret/db-cred; 第二行:能否 get secret/app-config。
  8. 在 /root/cks-secrets/encryption-config.yaml 中编写静态加密配置。 apiVersion: apiserver.config.k8s.io/v1,kind: EncryptionConfiguration, resources[0].resources 只有 secrets;providers 有两个,第一个为 aescbc (键名 key1,secret 为 32 字节值的 base64 编码),最后一个为 identity。

参考

创建 Opaque Secret

创建命名空间 cks-secrets,并在其中创建 Opaque Secret db-cred。 包含两个键:username(值为 app)和 password(值为 pr0d-Db-Pass)。

使用 kubectl create secret generic --from-literal= 最快捷。不指定类型时默认为 Opaque。

Registry 凭据 Secret

在 cks-secrets 中创建类型为 kubernetes.io/dockerconfigjson 的 Secret registry-cred。 服务器为 registry.cks.local,用户名为 ci,密码为 ci-token。

类型固定的 Secret,其数据键名也固定。dockerconfigjson 类型只使用 .dockerconfigjson 这一个键。

TLS Secret

在 cks-secrets 中创建类型为 kubernetes.io/tls 的 Secret shop-tls。tls.crt 和 tls.key 均不得为空。

必须同时包含 tls.crt 和 tls.key 两个键,API 服务器才会接受。

以环境变量注入

在 cks-secrets 中创建 Pod env-app(容器名称 app,镜像 nginx:1.27-alpine)。 容器的 envFrom[0].secretRef.name 为 db-cred。

envFrom 的 secretRef 会将 Secret 的所有键展开为环境变量。虽然方便,但要记住这些值会原样留在进程环境中。

以卷挂载并收紧权限

在 cks-secrets 中创建 Pod vol-app(容器名称 app)。卷名称为 db, secret.secretName 为 db-cred,secret.defaultMode 为 0400(十进制 256), 容器将该卷挂载到 /etc/db,并设置 readOnly: true。

defaultMode 在 YAML 中使用八进制编写,保存时会转为十进制。0400 表示仅所有者可读。

不可变 Secret

在 cks-secrets 中创建 Opaque Secret app-config。唯一的键为 mode(值为 strict), immutable 为 true。

启用 immutable: true 后无法修改数据,只能删除并重新创建,同时也能降低 kubelet 的 watch 负载。

限制为只能读取特定 Secret

在 cks-secrets 中创建 ServiceAccount app 和 Role db-cred-reader。 apiGroups 为核心组,resources 为 secrets,resourceNames 仅为 db-cred, verbs 仅为 get。通过 RoleBinding app-db-cred 绑定给 SA app。 然后按顺序将两个问题的答案(yes/no)分两行保存到 /root/cks-secrets/can-i.txt。第一行:SA app 能否 get secret/db-cred; 第二行:能否 get secret/app-config。

在 Role 中使用 resourceNames 固定名称后,只能读取该 Secret。使用 auth can-i 时以 TYPE/NAME 格式询问并确认结果。

静态加密配置文件

在 /root/cks-secrets/encryption-config.yaml 中编写静态加密配置。 apiVersion: apiserver.config.k8s.io/v1,kind: EncryptionConfiguration, resources[0].resources 只有 secrets;providers 有两个,第一个为 aescbc (键名 key1,secret 为 32 字节值的 base64 编码),最后一个为 identity。

Provider 列表的顺序具有意义:写入使用第一个 Provider,读取则按顺序尝试。错误放置 identity 会退回明文存储。