[K8S小白问题集] - K8S里的Secret是什么?

从技术底层拆解,K8S 的 Secret 是"被设计用来存放敏感数据的原生 API 对象",但它的安全边界经常被误解------它不是保险箱,而是"带标签的信封",真正的安全取决于你如何封存这个信封。

一、Secret 的本质:它到底是什么?

1.1 数据结构

Secret 在 etcd 中就是一个扁平的键值对资源对象 ,与 ConfigMap 结构几乎一致,区别仅在于 type 字段和语义暗示:

apiVersion: v1
kind: Secret
metadata:
name: db-password
namespace: prod-core
type: Opaque # 类型标记
data:
password: cGFzc3dvcmQxMjM= # base64 编码的字符串

关键认知 :data 字段下的值是 base64 编码 ,不是加密。base64 的目的是"让二进制数据安全地穿越 JSON/YAML 文本协议",而不是"防止人类读取"。任何人拿到这个 YAML,执行 echo cGFzc3dvcmQxMjM= | base64 -d 立刻得到明文 password123。

1.2 三种核心类型

|-------------------------------------------------------------------------------------------------------------------------|------------------------------------|-----------------------------|
| 类型 | 用途 | 银行场景示例 |
| Opaque | 通用敏感数据(密码、API Key、证书私钥) | 数据库连接串、支付网关 AK/SK |
| kubernetes.io/tls | TLS 证书与私钥 | Ingress HTTPS 证书、国密 SM2 双证书 |
| kubernetes.io/dockerconfigjson | 镜像仓库拉取凭证 | Harbor 私有仓库认证 |
| kubernetes.io/service-account-token | ServiceAccount JWT(1.24 后已默认不自动创建) | Pod 访问 APIServer 的身份令牌 |


二、与用户验证的关系:间接但关键

2.1 Secret ≠ 用户身份验证体系

用户验证(Authentication) 是 APIServer 的入口安检,解决"你是谁":

  • X509 客户端证书(CN=system:admin)
  • OIDC Token(Keycloak/Dex + 银行 AD/LDAP)
  • Webhook Token 认证(对接银行统一身份平台)
  • Bootstrap Token(节点加入)

Secret 不直接参与上述流程 。用户拿着 kubeconfig 里的证书或 OIDC Token 去敲 APIServer 的门,APIServer 验证的是签发者(CA 或 IdP),而不是 Secret。

2.2 Secret 与授权(Authorization)的桥梁作用

Secret 的真正安全价值在于****"权限载体"****:

|--------------------------|------------------------------------------------------------------------------------------------------------------------------|
| 场景 | Secret 角色 |
| ServiceAccount Token | 虽然 1.24+ 默认使用 TokenRequest 投影(短期 Token),但传统 Secret 形式的 SA Token 曾是 Pod 访问 APIServer 的"通行证"。若该 Secret 泄露,攻击者可冒充 Pod 身份调用 API。 |
| 镜像拉取凭证 | imagePullSecrets 引用 Secret,kubelet 凭此从私有 Harbor 拉取镜像。若泄露,攻击者可拉取银行私有镜像分析漏洞。 |
| 应用层身份 | 业务容器通过挂载 Secret 获取数据库密码或第三方 API Key。Secret 是****"应用向外部系统证明身份"****的凭证,而非 K8S 集群内部的身份验证。 |

一句话澄清 :Secret 是"应用访问外部世界的护照",不是"人类访问 K8S 的身份证"。但护照丢了,应用就能以你的名义干坏事。

三、能看到明文吗?三个层面的真相

3.1 层面一:etcd 中------默认完全明文

如果不做任何额外配置,Secret 在 etcd 中就是裸奔的 protobuf 编码数据。etcd 本身没有内置加密:

直接读取 etcd(如果有权限),你能看到:

key: /registry/secrets/prod-core/db-password

value: {"password":"cGFzc3dvcmQxMjM="} (base64,但 etcd 客户端自动解码后就是明文)

这是 K8S Secret 最大的安全盲区。etcd 是集群的"大脑",一旦攻击者突破 Master 节点或 etcd 节点,所有 Secret 一览无余。

3.2 层面二:APIServer 返回------base64 编码

通过 kubectl get secret db-password -o yaml 或 API 调用,APIServer 返回的是 base64 编码值。这不是加密,是"防传输层意外截断"的编码。任何有 get secret 权限的人都能瞬间解码。

3.3 层面三:容器内------明文文件或环境变量

Secret 被消费时,彻底暴露为明文:

方式一:Volume 挂载(推荐,相对安全)

volumeMounts:

  • name: secret-vol
    mountPath: /etc/secrets
    readOnly: true

容器内:cat /etc/secrets/password → 明文 password123

方式二:环境变量(不推荐,风险高)

env:

  • name: DB_PASSWORD
    valueFrom:
    secretKeyRef:
    name: db-password
    key: password

容器内:echo $DB_PASSWORD → 明文

风险:/proc/<pid>/environ 任何同节点进程可读;docker inspect 可见

结论 :Secret 在全生命周期中默认都是明文可读的 ,它提供的唯一保护是RBAC 权限隔离 (谁能看 Secret)和传输层 TLS,而不是内容本身的机密性。

四、加密机制:原生能力与金融级增强

4.1 K8S 原生静态加密(Encryption at Rest)

K8S 1.7+ 支持通过 EncryptionConfiguration 在写入 etcd 前对 Secret 进行加密:

/etc/kubernetes/enc/encryption-config.yaml

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:

  • resources:
  • secrets # 仅加密 Secret,也可加 configmaps
    providers:
  • aescbc: # 算法 1:AES-CBC(已废弃,不推荐)
    keys:
  • name: key1
    secret: <base64-encoded-32-byte-key>
  • aesgcm: # 算法 2:AES-GCM(推荐,认证加密)
    keys:
  • name: key1
    secret: <base64-encoded-32-byte-key>
  • secretbox: # 算法 3:XSalsa20 + Poly1305
    keys:
  • name: key1
    secret: <base64-encoded-32-byte-key>
  • identity: {} # 兜底:不加密(用于轮换过渡)

工作机制

  1. 用户创建 Secret → APIServer 接收明文
  2. APIServer 根据 EncryptionConfiguration 选择 provider
  3. 在写入 etcd 前,AES-GCM 加密 value 部分
  4. etcd 中存储的是密文 + 加密元数据
  5. APIServer 读取时自动解密,对用户透明

关键风险

  • 密钥管理 :encryption-config.yaml 中的密钥是明文写在文件系统上的。如果 Master 节点被攻破,加密密钥和密文在一起,等于没加密。
  • 密钥轮换 :原生不支持自动轮换,需手动更新配置并触发全量重写(kubectl get secrets --all-namespaces -o json | kubectl replace -f -),银行大集群耗时极长。

4.2 金融级增强:对接 KMS / Vault

银行不会满足于"文件里放个 AES 密钥",必须对接外部密钥管理系统

|------------------------|---------------------------------------------------------------|-------------------------|
| 方案 | 原理 | 银行适用性 |
| KMS Provider(云厂商) | APIServer → 阿里云 KMS / AWS KMS / Azure Key Vault → 数据密钥(DEK)加密 | 公有云场景首选,但密钥托管在云厂商 |
| Vault KMS Provider | APIServer → HashiCorp Vault(Transit 引擎)→ 自动密钥轮换 + HSM 保护 | 私有云/信创首选,密钥不出 Vault |
| 国密改造 | 原生 AES-GCM 替换为 SM4-GCM,APIServer 加密 provider 插件化改造 | 等保/信创合规要求 |

对接 Vault 的 EncryptionConfiguration(概念性)

providers:

  • kms:
    name: vault-kms
    endpoint: unix:///var/run/kms-plugin/vault.sock # KMS Plugin sidecar
    cachesize: 1000
    timeout: 3s

国密特化 :金融核心系统若需 SM4 加密,通常需基于开源 K8s 二次开发或采用博云、青云、华为 CCE 等国产发行版,它们内置了国密加密 provider。

4.3 动态注入:External Secrets Operator(银行最佳实践)

更安全的模式是"Secret 不在 K8S 中长期存储":

Vault(银行 HSM 保护)

├──► External Secrets Operator(K8s Operator)
│ │
│ └──► 定期同步为 K8s Secret(存活期 < 1h)
│ │
│ └──► 业务 Pod 挂载

└──► 动态数据库凭据(Vault 自动生成,自动过期)

优势

  • 即使 etcd 被攻破,Secret 是短期有效的
  • 密码泄露后自动轮转,无需人工改 YAML
  • 审计在 Vault 端完成,满足等保要求

五、银行级 Secret 治理实践

5.1 必须遵守的红线

|-----------------|-------------------------------------------------------------------------|
| 风险 | 技术对策 |
| etcd 明文泄露 | 必须启用 EncryptionConfiguration,优先 AES-GCM;信创环境评估 SM4 |
| Secret 权限过宽 | Kyverno/OPA 禁止 default ServiceAccount 自动挂载;禁止 cluster-admin 读取所有 Secret |
| 环境变量泄露 | 强制 Volume 挂载(readOnly: true,权限 0400);禁止 envFrom 引用 Secret |
| Git 仓库泄露 | 禁止 Secret YAML 入 Git;使用 Sealed Secrets / SOPS / External Secrets |
| 镜像层残留 | Dockerfile 禁止 COPY 包含 Secret 的文件;BuildKit Secret 挂载构建 |
| 审计盲区 | 所有 get secret / create secret / delete secret 操作记录审计日志,留存 6 个月 |

5.2 等保与 PIPL 适配

  • 等保 2.0/3.0:要求"重要数据存储保密性",Secret 必须静态加密,加密密钥分级保护
  • PIPL:若 Secret 包含个人信息(如客户登录 Token),其处理需满足最小必要原则,泄露需上报

六、一句话讲透 Secret

K8S Secret 是一个"权限控制下的 base64 信封",默认不防内鬼、不防 etcd 攻破、不防节点提权。它的安全=RBAC 权限隔离 + 可选的 etcd 静态加密 + 金融级场景下必须叠加的 Vault 动态注入/HSM 国密保护。

它不是保险箱,而是"需要额外上锁的信封"。银行生产环境中,信封里的内容必须被加密,钥匙必须放在 HSM 里,信封的开启必须被审计。

相关推荐
IT利刃出鞘1 天前
K8S--解决dashboard一直Pending的问题
k8s
9命怪猫2 天前
[K8S小白问题集] - APIServer接受到的API调用都是什么样的?与http请求的API差别很大吗?
k8s
冷小鱼2 天前
从 Docker 到容器编排:框架选型与指令详解实战指南
运维·docker·容器·k8s·docker compose·docker swarm
wxh_无香花自开2 天前
k8s证书到期处理
k8s
云游牧者4 天前
K8S故障排查三板斧-CSDN博客
运维·docker·云原生·kubernetes·k8s·容器化·故障排查
@王先生14 天前
【K8S-ETCD初始化三节点集群】
前端·chrome·k8s·etcd·集群
牛奶咖啡134 天前
CI/CD——在jenkins中构建流程实现springboot项目的自动化构建与部署
java·ci/cd·k8s·jenkins·springboot·springboot制作镜像·使用源码项目制作镜像
脑子加油站7 天前
K8S-Ingress资源对象
算法·贪心算法·k8s
~黄夫人~9 天前
Kubernetes 入门到实战:概念详解 + kubeadm 安装 + 节点克隆全流程
linux·运维·学习·k8s·集群