概述

你有没有这样写过代码?

# 危险!绝对不要这样做!
env:
  - name: DB_PASSWORD
    value: "mySuperSecret123!"

或者把 API Key 直接打包进 Docker 镜像?

在 Kubernetes 中,这类敏感信息(密码、Token、证书等)应该用 Secret 来管理。

什么是 Secret

Secret 是 Kubernetes 的一种资源对象,专门用于:

  • 存储敏感数据,如:
    • 数据库密码
    • OAuth Token
    • TLS 证书私钥
    • 第三方 API 密钥
  • 将敏感信息与应用代码/镜像解耦
  • 通过 RBAC 控制访问权限

核心原则:敏感信息绝不硬编码,绝不进 Git,绝不进镜像!

Secret vs ConfigMap

特性 ConfigMap Secret
用途 非敏感配置(日志级别、开关) 敏感信息(密码、密钥)
存储格式 明文(YAML 中直接可见) Base64 编码(非加密!)
默认权限 所有 Pod 可读(需显式引用) 同左,但可通过 RBAC 限制
安全性 (需配合其他措施)

说明:
Secret 并不是“加密存储”!它只是 Base64 编码(可轻松解码)。
真正的安全依赖于:

  • etcd 启用加密(集群管理员配置)
  • 严格的 RBAC 权限控制
  • 不将 Secret 写入日志或输出

创建 Secret 的三种方式

方式 1:从字面值创建(适合少量密钥)

kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='S3cr3tP@ss!'

查看内容(注意:会显示 Base64 编码):

kubectl get secret db-secret -o yaml

输出片段:

data:
  username: YWRtaW4=           # echo -n "admin" | base64
  password: UzNjcjN0UEBzc2Eh   # echo -n "S3cr3tP@ss!" | base64

你可以用 echo "UzNjcjN0UEBzc2Eh" | base64 -d 解码回原文

方式 2:从文件创建(适合证书、密钥文件)

假设你有:

  • tls.key(私钥)
  • tls.crt(证书)

创建 Secret:

kubectl create secret tls my-tls-secret \
  --cert=tls.crt \
  --key=tls.key

这是创建 HTTPS 证书 Secret 的标准方式

方式 3:从 YAML 文件定义(最灵活,推荐)

创建 secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque  # 默认类型,用于通用密钥
data:
  # 注意:必须是 Base64 编码!
  database_password: UzNjcjN0UEBzc2Eh
  api_key: QVBJLTIwMjQtMTIzNDU2Nzg5MAo=

或者用 stringData(自动编码,更友好):

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  # 直接写明文,K8s 自动转 Base64
  database_password: "S3cr3tP@ss!"
  api_key: "API-2024-1234567890"

强烈推荐用 stringData!避免手动编码出错。

应用:

kubectl apply -f secret.yaml

在 Pod 中使用 Secret

场景 1:作为环境变量注入(简单但有风险)

# deployment-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: my-app:1.0
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database_password

注意:如果应用打印环境变量(如调试日志),密码会泄露

场景 2:挂载为文件(更安全,推荐)

# deployment-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: my-app:1.0
        volumeMounts:
        - name: secret-volume
          mountPath: "/etc/secrets"
          readOnly: true   # 必须只读!
      volumes:
      - name: secret-volume
        secret:
          secretName: app-secrets

效果:

  • 容器内 /etc/secrets/database_password 文件内容 = 密码原文
  • 应用通过读文件获取密码(如 fs.readFileSync('/etc/secrets/database_password')

优势

  • 不会出现在环境变量中
  • 文件权限默认为 644,只有容器内进程可读
  • 更符合安全最佳实践

实战:部署一个连接数据库的 Python 应用

Step 1:创建 Secret

db-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: postgres-credentials
type: Opaque
stringData:
  username: "app_user"
  password: "My$tr0ngP@ss!"

Step 2:编写 Deployment(挂载为文件)

python-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-db-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-db
  template:
    metadata:
      labels:
        app: python-db
    spec:
      containers:
      - name: app
        image: python:3.9-slim
        command: ["sh", "-c"]
        args:
          - |
            USERNAME=$(cat /etc/secrets/username)
            PASSWORD=$(cat /etc/secrets/password)
            echo "Connecting to DB as $USERNAME..."
            # 这里可以写真实连接逻辑
            sleep 3600
        volumeMounts:
        - name: secret-vol
          mountPath: "/etc/secrets"
          readOnly: true
      volumes:
      - name: secret-vol
        secret:
          secretName: postgres-credentials

Step 3:部署并验证

kubectl apply -f db-secret.yaml
kubectl apply -f python-app.yaml

# 查看日志(不应出现密码!)
kubectl logs -l app=python-db

输出:

Connecting to DB as app_user...

最佳实践

建议 说明
✅ 使用 stringData 创建 Secret 避免手动 Base64
✅ 挂载为文件而非环境变量 减少泄露风险
✅ 设置 readOnly: true 防止应用意外修改
✅ 限制 RBAC 权限 只允许必要服务账户读取
✅ 启用 etcd 加密(集群级) 防止磁盘泄露(需管理员操作)
❌ 不要 kubectl get secret -o yaml 后截图发群里! Base64 很容易解码
❌ 不要把 Secret 提交到 Git 即使是私有仓库也不行!

终极建议:生产环境考虑使用 外部密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager),Secret 仅作临时中转。

常见问题

1:Secret 是加密的,所以是安全的

实际只是 Base64 编码!真正的安全靠 etcd 加密 + RBAC。

2:用了 Secret 就万无一失吗?

→ 如果应用把密码打印到日志,照样泄露!安全是体系工程。

说明:
Secret 是 Kubernetes 提供的“敏感信息传递机制”,不是“保险箱”
它解决了“如何不把密码写进代码”的问题,但不能替代整体安全策略

总结

问题 Secret 解法
密码写死在 YAML? ✅ 外部化为 Secret
镜像包含 API Key? ✅ 运行时注入
多环境密钥混乱? ✅ 创建 prod-secrets / staging-secrets
团队共享密码? ✅ 通过 RBAC 控制访问
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐