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/tls (TLS 证书)。第 31 篇配置 HTTPS Ingress 时创建的 counter-tls Secret 就是 TLS 类型。
三、创建 Secret 的四种方式
3.1 从字面量创建
bash
kubectl create secret generic db-secret \
--from-literal=username=flaskapp \
--from-literal=password=MyS3cretP@ss
输出:
验证 Secret 的"半隐藏"特性:
bash
kubectl describe secret db-secret
# Name: db-secret
# Namespace: default
# Type: Opaque
# Data
# ====
# password: 13 bytes
# username: 8 bytes
kubectl describe 只显示值的字节数,不显示明文。但要查看明文很容易:
bash
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d
# MyS3cretP@ss
这就是为什么 Secret 本身需要配合 RBAC 权限控制------任何有 get secret 权限的用户都可以解码看到明文。这也是为什么生产环境中需要静态加密和 Sealed Secrets(本章第四部分)来增强安全性。
3.2 从文件创建
bash
# 准备文件
echo -n "flaskapp" > username.txt
echo -n "MyS3cretP@ss" > password.txt
kubectl create secret generic db-secret-from-file \
--from-file=./username.txt \
--from-file=./password.txt
3.3 声明式 YAML(推荐)
bash
apiVersion: v1
kind: Secret
metadata:
name: db-secret-yaml
type: Opaque
data:
username: Zmxhc2thcHA= # "flaskapp" 的 base64 编码
password: TXlTM2NyZXRQQHNz # "MyS3cretP@ss" 的 base64 编码
注意 data 字段中的值必须是 base64 编码 。如果你不想手动编码,可以用 stringData 字段(仅用于创建,kubectl get -o yaml 不会显示 stringData):
bash
apiVersion: v1
kind: Secret
metadata:
name: db-secret-string
type: Opaque
stringData:
username: flaskapp
password: MyS3cretP@ss
stringData 中的值不需要 base64 编码,K8s 会自动转换。推荐在 YAML 中使用 stringData 提高可读性,但注意这个 YAML 文件本身不应提交到 Git。
bash
kubectl apply -f db-secret.yaml
3.4 使用 kustomization.yaml 管理(进阶)
对于需要管理多个环境 Secret 的场景,Kustomize 提供了更系统的方法:
bash
# kustomization.yaml
secretGenerator:
- name: db-secret
literals:
- username=flaskapp
- password=MyS3cretP@ss
这种方式下,Secret 的值不在最终生成的 YAML 中直接出现,且 Kustomize 会自动为 Secret 名添加哈希后缀,支持 Deployment 自动滚动更新。
四、将 Secret 注入 Pod
和 ConfigMap 一样,Secret 支持三种注入方式。以下是具体的 YAML 写法:
环境变量注入:
bash
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
一次性注入整个 Secret:
bash
envFrom:
- secretRef:
name: db-secret
文件挂载:
bash
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 中配置 EncryptionConfiguration:
bash
apiVersion: 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 可以读取 Secret:
bash
apiVersion: 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:
bash
# 在 Minikube 集群中安装(通过 Helm,第 39 篇会详解)
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets
使用 kubeseal 加密 Secret:
bash
# 创建普通 Secret(不提交到 Git)
kubectl create secret generic db-secret --from-literal=password=MyS3cretP@ss --dry-run=client -o yaml
# 使用 kubeseal 加密
kubectl create secret generic db-secret --from-literal=password=MyS3cretP@ss --dry-run=client -o yaml | \
kubeseal --format yaml > db-sealed-secret.yaml
生成的 db-sealed-secret.yaml 中的密码已被加密,可以安全提交到 Git。部署时,Sealed Secrets Controller 自动解密为普通 Secret,Pod 正常使用。这样既遵守了 GitOps 的"Git 是唯一真相来源"原则,又保证了敏感信息的安全性。
七、命令速查表
八、本篇总结
-
Secret vs ConfigMap:Secret 专门存储敏感信息,支持多种预定义类型,配合 RBAC 和静态加密实现多层安全防护。
-
三种注入方式 :环境变量、
envFrom批量注入、文件挂载(推荐,支持 tmpfs 内存存储)。 -
安全不是默认的:裸 Secret 只是 base64 编码。生产环境必须配置静态加密 + RBAC 最小权限 + 考虑外部密钥管理系统。
-
GitOps 方案:Sealed Secrets 解决了敏感信息存入 Git 的安全问题,是实现全声明式部署的关键组件。
本篇完成了配置管理的闭环------ConfigMap 管理非敏感配置,Secret 管理敏感信息。下一篇------第 34 篇:存储基础:emptyDir 与 hostPath,我们将进入 K8s 存储体系的学习,从最简单的临时存储开始,逐步深入到 PV/PVC 和 StorageClass。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !