- 文档
- 教程
- 云原生
【免费下载链接】k8s-tutorials
k8s tutorials | k8s 教程
导读
在 Kubernetes 中,ConfigMap 负责承载非敏感配置,但当配置内容涉及数据库密码、令牌、API Key 等敏感信息时,明文存储显然不可接受。本篇以 k8s-tutorials 仓库中的 Secret 教程(docs/secret.md)为骨架,结合仓库内的 secret/ 实战源码与 helm-charts/hello-helm 模板,系统讲解 Secret 的资源定义、Base64 编码、Pod 环境变量注入(secretKeyRef)、应用侧读取以及 Helm 场景下的模板化密钥管理,读完即可在真实集群中安全地交付"加密配置"。
一、为什么需要 Secret:ConfigMap 的局限
前一篇教程(docs/configmap.md)展示了用 ConfigMap 按 namespace 隔离不同环境的DB_URL。ConfigMap 的定位是存放非机密性的键值对数据(且单对象数据量不能超过 1 MiB),它天然不适合承载敏感内容:
- ConfigMap 的
data字段以明文形式存放,kubectl get configmap -o yaml即可直接看到全部配置内容; - 若把数据库密码写进 ConfigMap,等同于把密码明文暴露在 API Server 与 etcd 中,任何能读取 ConfigMap 的人都能拿到凭据。
Secret 正是为这类场景设计的:它同样是键值对结构,与 ConfigMap 的资源定义几乎一致,但语义上专门用于保存少量敏感信息,例如密码、令牌或密钥。区别在于两点——kind为Secret,以及data中的 value 需要经过Base64 编码。
二、Secret 的安全边界与官方安全实践
需要特别澄清一个常见误解:Secret 的 Base64 编码不是加密。它只是为了让 value 能够安全地承载任意字节内容(包括二进制),任何拿到编码串的人都可以用一条命令还原。真正的安全性来自 Kubernetes 平台层的防护,官方文档为此给出了明确的基线建议,本仓库教程也原文引用了这些要点:
- etcd 中的静态加密:默认情况下,Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。因此必须为 Secret 启用静态加密(Encrypting Secret Data at Rest)。
- RBAC 权限收敛:启用或配置 RBAC 规则来限制读取和写入 Secret 的数据(包括通过间接方式)。注意一个隐含风险:被准许创建 Pod 的人也会隐式地被授权获取 Secret 内容(例如通过环境变量注入间接读取),这是"间接访问"通道,例如创建 Deployment 的能力同样适用。
- 最小化 Secret 的创建与替换权限:在适当的情况下,还可以使用 RBAC 等机制限制允许哪些主体创建新 Secret 或替换现有 Secret。
关键结论:Base64 解决的是"数据格式"问题,etcd 静态加密 + RBAC 解决的是"访问控制"问题,两者缺一不可。本仓库教程明确指出,在生产实践中可以通过 pipeline 或专业的密钥管理服务(如 AWS KMS)进行密钥管理,从而大大减少安全事故。
三、Secret 的资源定义:data 与 stringData
3.1 用 Base64 编码 value
Secret 的data字段要求 value 必须是 Base64 编码后的字符串。本仓库教程给出了最常用的编解码命令:
echo "db_password" | base64 # ZGJfcGFzc3dvcmQK echo "ZGJfcGFzc3dvcmQK" | base64 -d # db_password将编码后的值填入对应的 key-value 中,就得到仓库 secret/hellok8s-secret.yaml 中的完整资源定义:
# hellok8s-secret.yaml apiVersion: v1 kind: Secret metadata: name: hellok8s-secret data: DB_PASSWORD: "ZGJfcGFzc3dvcmQK"3.2 stringData:免去手动编码
除了data,Secret 还提供stringData字段:写入时不需要 Base64 编码,Kubernetes 会在写入 etcd 前自动完成编码转换。适合在编写资源文件时直接书写人类可读的明文值,例如:
apiVersion: v1 kind: Secret metadata: name: hellok8s-secret stringData: DB_PASSWORD: "db_password"需要注意:stringData是"写入时便利"机制,kubectl get secret -o yaml读回时仍会以 Base64 的data形式呈现;且同一 key 若同时出现在data与stringData中,stringData优先。生产环境建议用 CI 流水线生成 Secret 对象,避免把明文值提交进 Git 仓库。
四、在 Pod 中引用 Secret:环境变量注入 secretKeyRef
创建好 Secret 后,Pod 通过spec.containers[].env[].valueFrom.secretKeyRef将指定 key 注入为环境变量。仓库 secret/hellok8s.yaml 给出了完整示例:
# hellok8s.yaml apiVersion: v1 kind: Pod metadata: name: hellok8s-pod spec: containers: - name: hellok8s-container image: guangzhengli/hellok8s:v5 env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: hellok8s-secret key: DB_PASSWORD字段含义拆解(与 ConfigMap 章节的configMapKeyRef一一对应,可对照 docs/configmap.md 学习):
env.name:注入后容器内的环境变量名,应用代码读取时必须与此保持一致;valueFrom.secretKeyRef.name:要引用的 Secret 对象名(此处为hellok8s-secret);valueFrom.secretKeyRef.key:要取出的键名(此处为DB_PASSWORD)。
除环境变量外,Secret 还支持以 Volume 形式挂载:将spec.volumes[].secret.secretName指向 Secret,挂载后每个 key 会以文件形式出现在挂载目录中(/etc/secret-volume/DB_PASSWORD),适合应用按文件读取密钥的场景,且文件更新后通常无需重启 Pod 即可在挂载点感知(相比环境变量注入的"启动时一次性注入"更灵活)。本仓库教程以环境变量注入为主线,下文沿用该方式。
五、应用侧读取:从源码看 DB_PASSWORD 的使用
Secret 注入环境变量后,应用代码与其他环境变量无异。仓库 secret/main.go 展示了 v5 版本的 HTTP 服务:通过os.Getenv("DB_PASSWORD")读取数据库密码并随响应返回。
package main import ( "fmt" "io" "net/http" "os" ) func hello(w http.ResponseWriter, r *http.Request) { host, _ := os.Hostname() dbPassword := os.Getenv("DB_PASSWORD") io.WriteString(w, fmt.Sprintf("[v5] Hello, Kubernetes! From host: %s, Get Database Connect Password: %s", host, dbPassword)) } func main() { http.HandleFunc("/", hello) http.ListenAndServe(":3000", nil) }关键点:
os.Getenv("DB_PASSWORD")与 YAML 中env.name严格对应,这是"注入是否生效"的校验链路——若 Secret 不存在或 key 名拼错,容器启动时会报CreateContainerConfigError;- 仓库 secret/Dockerfile 采用多阶段构建(
golang:1.16-buster编译 →distroless/base-debian10运行),暴露3000端口,镜像 tag 为guangzhengli/hellok8s:v5; - 从源码结构看,教程刻意让响应体直接回显密码,目的是直观验证 Secret 注入是否成功,生产代码不应这样输出敏感信息。
六、完整部署与验证流程
Secret 的部署流程与 ConfigMap 完全一致(文档原话:"Secret 的使用方法和前面教程中 ConfigMap 基本一致"),依次执行即可:
# 1. 构建并推送 v5 镜像 docker build . -t guangzhengli/hellok8s:v5 docker push guangzhengli/hellok8s:v5 # 2. 先创建 Secret 资源 kubectl apply -f hellok8s-secret.yaml # secret/hellok8s-secret created # 3. 再创建引用该 Secret 的 Pod kubectl apply -f hellok8s.yaml # pod/hellok8s-pod created # 4. 端口转发后访问验证 kubectl port-forward hellok8s-pod 3000:3000 # 5. 另开终端 curl 验证注入结果 curl http://localhost:3000 # [v5] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect Password: db_password验证技巧:
- 先 apply Secret 再 apply Pod,避免因引用不存在的 Secret 导致 Pod 创建失败;
- 响应中的
Get Database Connect Password: db_password证明DB_PASSWORD已由secretKeyRef正确注入; - 查看实际生效值可执行
kubectl get secret hellok8s-secret -o yaml(注意读回的是 Base64 编码串)或kubectl exec hellok8s-pod -- env | grep DB_PASSWORD。
七、进阶:Helm 场景下的 Secret 模板化
在生产中,Secret 往往要按环境差异化(dev/test/prod 密码不同),直接维护多份 YAML 非常繁琐。仓库的 helm-charts/hello-helm 给出了模板化解法。
7.1 用 b64enc 函数在渲染期编码
helm-charts/hello-helm/templates/hellok8s-secret.yaml 中,Secret 的值不再手工 Base64,而是由 Helm 模板函数b64enc在渲染时自动编码:
# hellok8s-secret.yaml apiVersion: v1 kind: Secret metadata: name: {{ .Values.application.name }}-secret data: DB_PASSWORD: {{ .Values.application.hellok8s.database.password | b64enc }}这样 values 文件里可以存放明文密码(便于维护),渲染出的 Secret 却始终是 Base64 形式,一举两得。
7.2 values 按环境区分密码
默认值定义在 helm-charts/hello-helm/values.yaml:
application: name: hellok8s hellok8s: image: guangzhengli/hellok8s:v6 replicas: 3 message: "It works with Helm Values[v2]!" database: url: "http://DB_ADDRESS_DEFAULT" password: "db_password"dev 环境覆盖值定义在 helm-charts/hello-helm/values-dev.yaml:
application: hellok8s: message: "It works with Helm Values values-dev.yaml!" database: url: "http://DB_ADDRESS_DEV" password: "db_password_dev"通过helm install -f values-dev.yaml即可让 Secret 中的DB_PASSWORD自动渲染为 dev 环境的密码。
7.3 Deployment 中同时引用 ConfigMap 与 Secret
helm-charts/hello-helm/templates/hellok8s-deployment.yaml 展示了DB_URL(来自 ConfigMap)与DB_PASSWORD(来自 Secret)在同一容器中并存的完整模板,两个引用机制完全对称:
env: - name: DB_URL valueFrom: configMapKeyRef: name: {{ .Values.application.name }}-config key: DB_URL - name: DB_PASSWORD valueFrom: secretKeyRef: name: {{ .Values.application.name }}-secret key: DB_PASSWORD综合来看:明文配置走 ConfigMap,敏感配置走 Secret,两者结构对称、使用方式一致,这正是 k8s-tutorials 教程体系的连贯设计。
八、Secret 使用最佳实践小结
- 区分明文与敏感数据:非敏感的
DB_URL用 ConfigMap,密码、令牌、证书私钥等一律走 Secret; - 认清 Base64 的本质:它只是格式编码而非加密,安全底线是 etcd 静态加密 + RBAC 权限收敛,生产环境优先借助 pipeline / 专业密钥管理服务(如 AWS KMS)托管密钥;
- 善用
stringData:编写资源文件时免去手动 Base64,但注意读回时仍以data形式展示; - 控制暴露面:Secret 对象按最小权限创建与替换,并牢记"能创建 Pod 的人即能间接读取 Secret";
- 模板化落地:多环境场景用 Helm 的
b64enc+ values 分层覆盖,避免敏感值散落在各 YAML 中; - 注入方式选型:环境变量注入简单直接(启动时一次性生效),Volume 挂载更适合按文件读取且支持运行时感知更新。
九、参考资源
本仓库内可继续深入阅读的相关文件:
- 教程原文:docs/secret.md
- 实战源码与清单:secret/main.go、secret/hellok8s-secret.yaml、secret/hellok8s.yaml、secret/Dockerfile
- 前置对照章节:docs/configmap.md(ConfigMap 与 Secret 的结构/用法对比)
- Helm 模板化示例:helm-charts/hello-helm/templates/hellok8s-secret.yaml、helm-charts/hello-helm/templates/hellok8s-deployment.yaml、helm-charts/hello-helm/values.yaml、helm-charts/hello-helm/values-dev.yaml
- 文档
- 教程
- 云原生
【免费下载链接】k8s-tutorials
k8s tutorials | k8s 教程
相关推荐
Kubernetes Ingress 详解与实战教程:基于k8s-tutorials项目的网关配置指南
Kubernetes Ingress 详解与实战教程:基于k8s tutorials项目的网关配置指南 引言:为什么需要Ingress? 在现代微服务架构中,一
文档教程云原生MinIO on Kubernetes 的 TLS 安全接入配置指南:证书、Secret 与挂载实践
MinIO on Kubernetes 的 TLS 安全接入配置指南:证书、Secret 与挂载实践 本文围绕仓库 docs/tls/kubernetes/RE
后端存储对象存储分布式存储云原生2 条路径修好 Layui 标签页表单错乱:Tabs 切换后 Form 不渲染的排查与自查
2 条路径修好 Layui 标签页表单错乱:Tabs 切换后 Form 不渲染的排查与自查 如果你切到第二个 Tab,输入框整排塌掉、下拉框和日期选择器宽得像被
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考