Kubernetes Secret 让数据库密码离开镜像和 Pod 配置

前言: 昨天把图片预览接口的画质参数交给 ConfigMap 后,我顺手想把数据库密码也塞进去,省得再改镜像。可查了 Kubernetes 官方安全建议才发现,普通参数和凭证不该混在一起;更尴尬的是,把密码写进 Pod 配置一样会留下明文。于是我想弄清楚:

text 复制代码
1. 没有 Secret 时,密码通常被放在哪里,会留下什么麻烦?
2. 用了 Secret 后,密码是不是就一定安全了?

这篇只看一个测试用的假密码,弄清 Secret 怎样把凭证交给 Pod,不讨论外部密钥系统。

一. 画质能放进配置对象,密码怎么办

  1. 图片预览接口要连数据库。最省事的写法,是把连接密码放进镜像中的配置文件。开发环境可以跑,等测试和生产的密码不一样时,同一份程序又得分别打包。更糟的是,拿到镜像的人也可能拿到这份密码。

  2. 我第一反应是照搬上一篇:把 DB_PASSWORD 放在 ConfigMap ,由容器读取。这样至少不用重新打镜像。但密码仍然是普通配置,能读取该对象的人就能看到它。把值直接填在 Pod 的 env.value 里也不舒服:工作负载清单会跟着带上密码。

这张图重点看密码的落点:我们想让程序拿到它,却不想让镜像或工作负载清单带着值到处走。

二. 从"直接写进去"到"只写引用"

  1. 最粗暴的方案是镜像里放密码,打包时就固定了。稍好一点是在 Pod 模板里写环境变量,镜像能够复用,但配置清单依然含有明文。把密码换个位置,不等于解决了传播范围的问题。

  2. 官方把非机密数据交给 ConfigMap ,而把密码、令牌这类敏感数据交给 Secret 。工作负载配置只写"我要读取哪个 Secret 的哪个键",值放在另一个对象里。这样至少能把程序交付物、工作负载模板与凭证分开管理。

做法 密码放在哪里 改密码时要动哪里
写入镜像 镜像文件 重建并重新发布镜像
写入 Pod 模板 工作负载清单 修改模板并重建 Pod
使用 Secret 独立的 Secret 对象 更新凭证,并确认应用读取方式

这里的变化不是"密码消失了",而是 Pod 模板只保留引用,凭证的管理入口变得独立。

三. 把 Secret 当成单独交接的钥匙

  1. 如果把镜像想成一台已经装好的咖啡机,上一篇的画质参数是档位卡,数据库密码则更像仓库钥匙。换档位可以公开讨论,钥匙却需要单独保管,只有负责开门的人拿到。对应到这里:镜像是程序,ConfigMap 是普通参数,Secret 是要交给指定容器的凭证。

  2. 注意,这个类比只说明用途和交接范围 。它没有承诺钥匙进了 Secret 就会自动加密、自动轮换,或者阻止拿到钥匙的程序把它打印到日志里。官方安全实践明确提醒:Secret 的 data 使用 Base64 编码,编码不是加密;底层 etcd 默认也不会替它加密存储,需要管理员配置静态加密和访问权限。

这张图重点看"谁需要读取":普通参数和数据库凭证都可以独立于镜像,但凭证还要限制读取范围。

四. 用一个假密码看清交接过程

  1. 下面用 demo-password-only 作为无效的演示值 。先在独立命名空间创建 Secret ,再创建引用它的 Pod 。这里用 --from-literal 让步骤容易看懂;真实密码不宜直接写进终端命令,避免进入命令历史或被旁观者看到。实际环境应使用受控的凭证交付流程。
bash 复制代码
kubectl create namespace blog-secret-lab
kubectl -n blog-secret-lab create secret generic preview-db \
  --from-literal=password='demo-password-only'
kubectl -n blog-secret-lab apply -f demo.yaml
kubectl -n blog-secret-lab wait --for=condition=Ready pod/preview-secret-demo --timeout=120s
  1. demo.yaml 里最关键的是 secretKeyRef:它写的是对象名和键名,没有直接写密码值 。完整清单随文章归档。这里使用环境变量,是为了让读者容易观察交接结果;如果应用支持从文件读取,也可以按官方教程把 Secret 挂成卷。
yaml 复制代码
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: preview-db
        key: password # 注意:这里只写键名,不写密码值
  1. 可以检查环境变量是否存在,同时避免把值直接打印到共享终端或日志:
bash 复制代码
kubectl -n blog-secret-lab exec preview-secret-demo -- \
  sh -c 'test -n "$DB_PASSWORD" && echo "password received"'
kubectl -n blog-secret-lab describe secret preview-db

第二条命令显示键和字节数,不会显示明文值。需要排查时也别顺手把完整对象清单贴进工单。实验结束执行 kubectl delete namespace blog-secret-lab。

图中 Pod 模板只有"取哪把钥匙"的说明;最终拿到值的是容器内的进程。

五. 用了 Secret,还要防哪几种误会

  1. Secret 不是自动上锁的保险箱。谁能通过 API 读取它、底层是否启用静态加密,都取决于集群权限与配置。应用拿到值以后,也要避免在日志、错误信息或请求里泄漏。多个容器同处一个 Pod 时,也应只把凭证交给确实需要它的容器。

  2. 别被 data 字段里那串看不懂的字符骗了。Base64 很容易还原原文;把含真实密码的清单提交到 GitHub ,并不会因为它写在 Secret 里就安全。本文的清单只有引用,示例凭证是无效假值。

  3. 更新凭证以后,同一个容器中的环境变量不会自动变成新值;需要让工作负载创建新 Pod 。卷挂载可以最终收到更新,但应用是否重新读取文件仍要另外确认。这一点和上一篇的 ConfigMap 很像。选择交付方式时,要一起考虑密码轮换时应用怎样重新连接。

text 复制代码
先看 Secret 是否存在,以及 Pod 引用的名称和键是否正确
再看容器是否拿到值,不把真实密码打印出来
最后确认轮换后应用会不会重新读取或重新创建

这张图重点看最后一层:把凭证交到了容器,不代表它的存储、访问和使用过程都已经安全。

六. 总结:让密码单独交付,也要守住读取边界

  1. 回到图片预览接口,画质参数继续放在 ConfigMap ,数据库密码则由 Secret 单独交给需要它的容器。镜像和 Pod 模板不再写密码值,修改凭证也不必重做镜像。

  2. 下次遇到"服务要读密码"这类需求,我会先问三个问题:密码存放在哪里,哪些人和容器能读取,轮换后应用怎样拿到新值。Secret 负责提供专门的交付对象;权限、静态加密和应用侧保护,仍需要我们自己做。

这张图把判断顺序压成一条线:先把密码从镜像和普通配置里拿出来,再逐层确认谁能拿到它、何时换成新值。

相关推荐
闽林致远1 小时前
基于标准 C++ 的插件化多线程通用数据采集框架|支持自定义业务模块,Oracle/MySQL 入库、FTP 图片上传,Windows/Linux 跨平台部署
后端
doujiaozh1 小时前
协议演进实录:从明文哈希到 AES-GCM 加密,如何平滑升级?
后端·node.js
花卷持续成长1 小时前
慢SQL的整体优化思路
后端·mysql
Sashtok1 小时前
cpp基础知识(4)
后端
Sashtok1 小时前
cpp基础知识(6)
后端
用户2145549310151 小时前
VeapAI 自然语言操作实战|第 02 篇:语义层——把系统讲给模型听的四个构件
前端·后端
斑鸠喳喳1 小时前
期货模式 FutureTask
后端
Thneonl1 小时前
一次 rebalance,全组停摆:Kafka lag 从 0 到百万的事故复盘
后端·架构
badhope1 小时前
AI Agent安全治理实战:从API密钥泄露到沙箱隔离的完整防线
后端·llm·agent