跳到主要内容

⚙️ 配置与密钥管理

📋 ConfigMap 基础

ConfigMap 用于将配置数据以键值对形式存储,供 Pod 使用。适合存储非敏感配置,如配置文件、环境变量等。

创建 ConfigMap

# 从字面量创建
kubectl create configmap app-config \
--from-literal=database.url=localhost:3306 \
--from-literal=database.name=mydb

# 从文件创建
kubectl create configmap app-config \
--from-file=config.yaml \
--from-file=nginx.conf

# 从目录创建(目录中所有文件成为键值对)
kubectl create configmap app-config \
--from-file=./config-dir/

# 查看 ConfigMap
kubectl get configmap app-config -o yaml

ConfigMap YAML 定义

apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
# 简单键值对
database.url: 'localhost:3306'
database.name: 'mydb'
log.level: 'info'

# 配置文件(多行文本)
nginx.conf: |
server {
listen 80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html;
}
}

# 属性文件
app.properties: |
app.name=MyApplication
app.version=1.0.0
app.debug=true

🔑 Secret 基础

Secret 用于存储敏感信息,如密码、Token、密钥等。与 ConfigMap 不同,Secret 数据以 base64 编码存储(并非加密)。

创建 Secret

# 从字面量创建
kubectl create secret generic db-secret \
--from-literal=username=admin \
--from-literal=password='S3cur3P@ss!'

# 从文件创建
kubectl create secret generic tls-secret \
--from-file=tls.crt=server.crt \
--from-file=tls.key=server.key

# 创建 Docker registry Secret(拉取私有镜像用)
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=admin \
--docker-password=password \
--docker-email=admin@example.com

Secret YAML 定义

apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: default
type: Opaque
data:
# base64 编码的值
username: YWRtaW4= # admin
password: UDNhcjNQQHNzIQ== # S3cur3P@ss!
stringData: # 明文,kubectl 会自动编码
host: 'db.example.com'
port: '3306'

:::warning Secret 安全注意事项

  • Base64 不是加密:任何人都可以解码
  • etcd 默认不加密:需要启用 Encryption at Rest
  • RBAC 控制访问:限制 Secret 的读取权限
  • 使用外部密钥管理:生产环境推荐使用 Vault、AWS Secrets Manager 等 :::

🔄 使用配置:环境变量 vs 卷挂载

方式一:环境变量

apiVersion: v1
kind: Pod
metadata:
name: env-var-pod
spec:
containers:
- name: app
image: myapp:1.0
env:
# 单个键值对
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database.url

# 从 Secret 读取
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password

# 批量导入 ConfigMap 所有键值
- name: CONFIG_MAP_AS_ENV
valueFrom:
configMapRef:
name: app-config

# 批量导入 Secret 所有键值
- name: SECRET_AS_ENV
valueFrom:
secretRef:
name: db-secret

优点

  • 简单直接
  • 适合简单配置

缺点

  • 修改后需要重启 Pod
  • 无法通过 kubectl exec 查看
  • 可能泄露到日志、环境变量

方式二:卷挂载

apiVersion: v1
kind: Pod
metadata:
name: volume-mount-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
# ConfigMap 作为卷
- name: config-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: nginx.conf # 挂载为文件

# Secret 作为卷
- name: secret-volume
secret:
secretName: db-secret
defaultMode: 0400 # 文件权限
items:
- key: password
path: db-password

优点

  • 支持热更新(ConfigMap 修改后自动同步)
  • 可以挂载为文件
  • 权限控制更灵活

缺点

  • 需要应用支持读取文件
  • Secret 卷内容仍明文存储(需启用 Encryption at Rest)

:::tip 选择建议

  • 环境变量:适合简单、不常变的配置
  • 卷挂载:适合配置文件、需要热更新的场景
  • Secret:生产环境推荐使用外部密钥管理(Vault 等):::

🔐 外部密钥管理算子

生产环境不应将密钥存储在 Kubernetes Secret 中,而应使用外部密钥管理系统。

HashiCorp Vault

Vault 是企业级密钥管理工具,提供密钥轮换、审计日志、动态密钥等功能。

安装 Vault

# 使用 Helm 安装 Vault
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault --set "server.dev.enabled=true"

# 初始化 Vault
kubectl exec -it vault-0 -- vault operator init
kubectl exec -it vault-0 -- vault operator unseal <key>

# 配置 Kubernetes 认证
kubectl exec -it vault-0 -- vault auth enable kubernetes

Vault Agent Injector

apiVersion: v1
kind: Pod
metadata:
name: vault-injector-demo
annotations:
vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/agent-inject-secret-database: 'secret/data/database'
vault.hashicorp.com/role: 'myapp'
vault.hashicorp.com/agent-inject-template-database: |
{{- with secret "secret/data/database" -}}
export DB_PASSWORD="{{ .Data.data.password }}"
{{- end -}}
spec:
containers:
- name: app
image: myapp:1.0

AWS Secrets Manager

使用 External Secrets Operator (ESO) 从 AWS Secrets Manager 同步密钥。

安装 External Secrets Operator

# 使用 Helm 安装 ESO
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets-system --create-namespace

ESO 配置示例

# SecretStore 定义(连接到 AWS Secrets Manager)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secretsmanager
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
secretRef:
accessKeyID:
name: aws-credentials
key: access-key-id
secretAccessKey:
name: aws-credentials
key: secret-access-key

---
# ExternalSecret 定义(从 AWS 同步密钥)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 300s # 每 5 分钟同步一次
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: db-secret # 生成的 Kubernetes Secret 名称
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: prod/database
property: username
- secretKey: password
remoteRef:
key: prod/database
property: password

GCP Secret Manager

# SecretStore for GCP
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: gcp-secretmanager
spec:
provider:
gcpsm:
projectID: my-project-123
auth:
workloadIdentity:
clusterLocation: us-central1
clusterName: my-cluster
projectID: my-project-123

:::tip 外部密钥管理对比 | 工具 | 特点 | 适用场景 | |------|------|---------| | HashiCorp Vault | 功能最全,支持动态密钥 | 企业级,需要完整密钥生命周期管理 | | AWS Secrets Manager | 云原生,与 AWS 深度集成 | AWS 环境 | | GCP Secret Manager | 云原生,与 GCP 深度集成 | GCP 环境 | | Azure Key Vault | 云原生,与 Azure 深度集成 | Azure 环境 | | External Secrets Operator | 统一接口,支持多后端 | 混合云、多云平台 | :::

🌍 多环境配置管理

在生产实践中,通常需要管理多个环境(dev、staging、prod)的配置。

方案 1:命名空间隔离

# dev 命名空间
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: dev
data:
env: 'development'
database.url: 'dev-db.example.com:3306'

---
# prod 命名空间
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
env: 'production'
database.url: 'prod-db.example.com:3306'

方案 2:Kustomize 覆盖

├── base/
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── configmap-patch.yaml
│ └── kustomization.yaml
└── prod/
├── configmap-patch.yaml
└── kustomization.yaml

base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- configmap.yaml
- deployment.yaml

overlays/prod/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- configmap-patch.yaml

overlays/prod/configmap-patch.yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
env: 'production'
database.url: 'prod-db.example.com:3306'

方案 3:Helm Values 文件

├── charts/
│ └── myapp/
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── values-dev.yaml
│ ├── values-staging.yaml
│ ├── values-prod.yaml
│ └── templates/

部署命令

# 开发环境
helm install myapp ./charts/myapp -f values-dev.yaml

# 生产环境
helm install myapp ./charts/myapp -f values-prod.yaml

:::tip 多环境管理建议

  • 开发/测试环境:使用 Kustomize 或 Helm
  • 生产环境:使用 Helm + GitOps(ArgoCD/Flux)
  • 密钥管理:使用 External Secrets Operator + 环境隔离
  • 配置版本控制:将配置存储在 Git,使用 PR 审核 :::

🔒 Encryption at Rest

Kubernetes 支持对 etcd 中的 Secret 进行加密存储。

配置 Encryption Provider

# encryption-provider-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- aescbc:
keys:
- name: key1
secret: c2VjcmV0LXBhc3NwaHJhc2UtZm9yLWVuY3J5cHRpb24K
- identity: {} # 允许明文读取(用于迁移)

启用加密

# 修改 kube-apiserver 配置
vim /etc/kubernetes/manifests/kube-apiserver.yaml

# 添加参数
--encryption-provider-config=/etc/kubernetes/encryption-provider-config.yaml

# 重启 API Server
systemctl restart kubelet

验证加密

# 查看 etcd 中的 Secret(应该是加密的)
ETCDCTL_API=3 etcdctl get /registry/secrets/default/db-secret

🛠️ 实用命令

# 查看 ConfigMap
kubectl get configmap
kubectl describe configmap <name>
kubectl get configmap <name> -o yaml

# 编辑 ConfigMap(会触发滚动更新)
kubectl edit configmap <name>

# 删除 ConfigMap
kubectl delete configmap <name>

# 查看 Secret(不显示值)
kubectl get secret
kubectl describe secret <name>

# 查看 Secret 值(需要解码)
kubectl get secret <name> -o jsonpath='{.data.password}' | base64 --decode

# 比较 ConfigMap 差异
kubectl diff -f configmap.yaml

# 批量导出 ConfigMap
kubectl get configmap -o yaml > all-configmaps.yaml

📚 最佳实践

  1. 分离配置与代码:配置文件不应打包在镜像中
  2. 使用版本控制:将 ConfigMap/Secret 定义存储在 Git
  3. 环境隔离:不同环境使用不同命名空间或配置
  4. 最小权限原则:使用 RBAC 限制 Secret 访问
  5. 启用加密存储:生产环境必须启用 Encryption at Rest
  6. 定期轮换密钥:使用 Vault 等工具自动化密钥轮换
  7. 审计密钥访问:记录谁访问了哪些密钥
  8. 使用外部密钥管理:生产环境避免使用 Kubernetes 原生 Secret

📚 参考资源