IT策士 10余年一线大厂经验专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章助你少走弯路。在第 32 篇中我们用 ConfigMap 管理了 Flask 应用的配置——FLASK_ENV、LOG_LEVEL、REDIS_HOST。这些都是可以公开查看的非敏感信息。但应用中还有另一类配置数据库密码、API 密钥、TLS 证书私钥。这些信息如果像 ConfigMap 一样明文存储和展示任何一个能执行kubectl describe configmap的人都能看到——这是严重的安全隐患。Kubernetes 为此提供了专门的Secret对象。但 Secret 本身只是做了 base64 编码并非真正的加密。今天这篇我们不仅要学会 Secret 的创建和注入更要搞清楚如何让 Secret 真正安全——包括静态加密、RBAC 权限控制以及如何通过 Sealed Secrets 将加密后的敏感信息安全地存入 Git。一、Secret 是什么和 ConfigMap 有什么区别Secret 是 K8s 中专门用于存储和管理敏感信息的 API 对象。从操作方式上看它和 ConfigMap 高度相似——都支持从字面量、文件、YAML 创建都可以注入为环境变量或挂载为文件。两者最核心的区别在于设计意图和默认安全策略重要澄清Secret 的 base64 编码不是加密。在 K8s 集群内部任何有权限读取 Secret 的人都可以轻松解码。Secret 真正的安全价值在于它与 RBAC 配合可以实现精细的权限隔离以及配合静态加密Encryption at Rest可以保护 etcd 中的敏感数据。在 Docker Compose 时代密码通常明文写在.env文件中虽然可以加入.gitignore避免提交但在运行环境中仍然以明文环境变量存在。Secret 比这种“约定式”做法更进一步——它在存储层、传输层和访问控制层提供了多层次的保护。二、Secret 的七种类型K8s 预定义了多种 Secret 类型通过type字段区分用途日常使用中最常见的是Opaque通用密码和kubernetes.io/tlsTLS 证书。第 31 篇配置 HTTPS Ingress 时创建的counter-tlsSecret 就是 TLS 类型。三、创建 Secret 的四种方式3.1 从字面量创建kubectl create secret generic db-secret\--from-literalusernameflaskapp\--from-literalpasswordMyS3cretPss输出验证 Secret 的“半隐藏”特性kubectl describe secret db-secret# Name: db-secret# Namespace: default# Type: Opaque# Data# # password: 13 bytes# username: 8 byteskubectl describe只显示值的字节数不显示明文。但要查看明文很容易kubectl get secret db-secret-ojsonpath{.data.password}|base64-d# MyS3cretPss这就是为什么 Secret 本身需要配合 RBAC 权限控制——任何有get secret权限的用户都可以解码看到明文。这也是为什么生产环境中需要静态加密和 Sealed Secrets本章第四部分来增强安全性。3.2 从文件创建# 准备文件echo-nflaskappusername.txtecho-nMyS3cretPsspassword.txt kubectl create secret generic db-secret-from-file\--from-file./username.txt\--from-file./password.txt3.3 声明式 YAML推荐apiVersion: v1 kind: Secret metadata: name: db-secret-yaml type: Opaque data: username:Zmxhc2thcHA# flaskapp 的 base64 编码password: TXlTM2NyZXRQQHNz# MyS3cretPss 的 base64 编码注意data字段中的值必须是base64 编码。如果你不想手动编码可以用stringData字段仅用于创建kubectl get -o yaml不会显示stringDataapiVersion: v1 kind: Secret metadata: name: db-secret-string type: Opaque stringData: username: flaskapp password: MyS3cretPssstringData中的值不需要 base64 编码K8s 会自动转换。推荐在 YAML 中使用stringData提高可读性但注意这个 YAML 文件本身不应提交到 Git。kubectl apply-fdb-secret.yaml3.4 使用 kustomization.yaml 管理进阶对于需要管理多个环境 Secret 的场景Kustomize 提供了更系统的方法# kustomization.yamlsecretGenerator: - name: db-secret literals: -usernameflaskapp -passwordMyS3cretPss这种方式下Secret 的值不在最终生成的 YAML 中直接出现且 Kustomize 会自动为 Secret 名添加哈希后缀支持 Deployment 自动滚动更新。四、将 Secret 注入 Pod和 ConfigMap 一样Secret 支持三种注入方式。以下是具体的 YAML 写法环境变量注入env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password一次性注入整个 SecretenvFrom: - secretRef: name: db-secret文件挂载volumes: - name: secret-volume secret: secretName: db-secret containers: - name: flask volumeMounts: - name: secret-volume mountPath: /app/secrets readOnly:true挂载后/app/secrets/下会为每个键生成一个文件如password文件内容是解码后的明文。readOnly: true防止容器内进程修改 Secret 数据。五、Secret 的安全加固5.1 静态加密K8s 支持对 etcd 中的 Secret 进行静态加密。这需要在 API Server 中配置EncryptionConfigurationapiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret:base64-encoded-32-byte-key- identity:{}配置后新创建的 Secret 会在写入 etcd 前加密读取时自动解密。这是防止 etcd 备份泄露导致密钥外泄的关键措施。5.2 RBAC 权限控制通过 RBAC 限制哪些用户和 ServiceAccount 可以读取 SecretapiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: secret-reader rules: - apiGroups:[]resources:[secrets]verbs:[get,list]resourceNames:[db-secret]# 只允许访问特定 Secret只授予应用运行所需的 ServiceAccount 最小权限不开放集群级别的 Secret 列表权限。5.3 企业级方案External Secrets Operator 与 CSI Driver对于需要与外部密钥管理系统如 AWS Secrets Manager、HashiCorp Vault、Azure Key Vault集成的生产环境K8s 社区提供了更安全的方案External Secrets Operator将外部密钥管理系统的密钥同步为 K8s Secret支持定期轮换。Secrets Store CSI Driver将外部密钥直接挂载为 Pod 的 tmpfs 卷密钥永远不会以 K8s Secret 形式存储在 etcd 中。这两类工具解决了密钥生命周期的完整问题——创建、轮换、撤销都可以在外部系统统一管理K8s 只负责消费。六、GitOps 安全的 Secret 管理在 GitOps 工作流中所有的 K8s 资源 YAML 都存储在 Git 中。但 Secret 的明文绝对不能提交到 Git。解决方案是Sealed Secrets——它允许你将 Secret加密后安全地提交到 Git只有集群内的控制器可以解密。部署 Sealed Secrets Controller# 在 Minikube 集群中安装通过 Helm第 39 篇会详解helm repoaddsealed-secrets https://bitnami-labs.github.io/sealed-secrets helminstallsealed-secrets sealed-secrets/sealed-secrets使用 kubeseal 加密 Secret# 创建普通 Secret不提交到 Gitkubectl create secret generic db-secret --from-literalpasswordMyS3cretPss --dry-runclient-oyaml# 使用 kubeseal 加密kubectl create secret generic db-secret --from-literalpasswordMyS3cretPss --dry-runclient-oyaml|\kubeseal--formatyamldb-sealed-secret.yaml生成的db-sealed-secret.yaml中的密码已被加密可以安全提交到 Git。部署时Sealed Secrets Controller 自动解密为普通 SecretPod 正常使用。这样既遵守了 GitOps 的“Git 是唯一真相来源”原则又保证了敏感信息的安全性。七、命令速查表八、本篇总结Secret vs ConfigMapSecret 专门存储敏感信息支持多种预定义类型配合 RBAC 和静态加密实现多层安全防护。三种注入方式环境变量、envFrom批量注入、文件挂载推荐支持 tmpfs 内存存储。安全不是默认的裸 Secret 只是 base64 编码。生产环境必须配置静态加密 RBAC 最小权限 考虑外部密钥管理系统。GitOps 方案Sealed Secrets 解决了敏感信息存入 Git 的安全问题是实现全声明式部署的关键组件。本篇完成了配置管理的闭环——ConfigMap 管理非敏感配置Secret 管理敏感信息。下一篇——第 34 篇存储基础emptyDir 与 hostPath我们将进入 K8s 存储体系的学习从最简单的临时存储开始逐步深入到 PV/PVC 和 StorageClass。想了解更多还可以去各个平台搜索「IT策士」一起升级 IT 思维