密钥管理:安全存储敏感信息
密钥管理:安全存储敏感信息
什么是密钥管理
密钥管理是指安全地存储、访问和轮换敏感信息(如密码、API密钥、证书等)的实践。良好的密钥管理可以防止敏感信息泄露。
密钥管理原则
密钥管理核心原则:
├── 最小权限: 只授予必要的访问权限
├── 加密存储: 密钥必须加密存储
├── 定期轮换: 定期更换密钥和密码
├── 审计日志: 记录所有密钥访问
└── 不可逆: 密钥不应以明文形式存储
Kubernetes Secrets
创建Secret
# 创建通用Secret
kubectl create secret generic app-secret \
--from-literal=username=admin \
--from-literal=password=secretpass
# 从文件创建Secret
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 docker-secret \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass \
--docker-email=user@example.com
Secret YAML定义
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
namespace: production
type: Opaque
data:
username: YWRtaW4= # base64 encoded
password: cGFzc3dvcmQ=
stringData:
api-key: "my-api-key" # 自动base64编码
在Pod中使用Secret
# pod-with-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: tls-secret
外部密钥管理
HashiCorp Vault
# 安装Vault
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault -n vault
# 配置Kubernetes认证
vault auth enable kubernetes
vault write auth/kubernetes/config \
kubernetes_host=https://kubernetes.default.svc
# 创建策略
vault policy write app-policy - << 'EOF'
path "secret/data/app/*" {
capabilities = ["read"]
}
path "database/creds/readonly" {
capabilities = ["read"]
}
EOF
# 绑定到Kubernetes角色
vault write auth/kubernetes/role/app-role \
bound_service_account_names=app-sa \
bound_service_account_namespaces=production \
policies=app-policy \
ttl=1h
Vault Agent注入
# vault-agent-injector.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "app-role"
vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/readonly"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "database/creds/readonly" -}}
{
"username": "{{ .Data.username }}",
"password": "{{ .Data.password }}"
}
{{- end }}
spec:
serviceAccountName: app-sa
containers:
- name: app
image: myapp:latest
AWS Secrets Manager
#!/usr/bin/env python3
# aws-secrets-manager.py
import boto3
import json
from botocore.exceptions import ClientError
class SecretsManager:
def __init__(self, region_name='us-east-1'):
self.client = boto3.client('secretsmanager', region_name=region_name)
def get_secret(self, secret_name):
try:
response = self.client.get_secret_value(SecretId=secret_name)
return json.loads(response['SecretString'])
except ClientError as e:
raise e
def create_secret(self, secret_name, secret_value):
try:
self.client.create_secret(
Name=secret_name,
SecretString=json.dumps(secret_value)
)
except ClientError as e:
raise e
def rotate_secret(self, secret_name):
self.client.rotate_secret(SecretId=secret_name)
# 使用示例
secrets_manager = SecretsManager()
db_creds = secrets_manager.get_secret('prod/database/credentials')
密钥轮换
自动化轮换脚本
#!/bin/bash
# rotate-secrets.sh
SECRET_NAME=$1
NEW_PASSWORD=$(openssl rand -base64 32)
echo "轮换密钥: $SECRET_NAME"
# 1. 更新密钥
kubectl create secret generic $SECRET_NAME \
--from-literal=password=$NEW_PASSWORD \
--dry-run=client -o yaml | kubectl apply -f -
# 2. 重启相关Pod
kubectl rollout restart deployment -l app=app-name
# 3. 验证
sleep 30
kubectl get pods -l app=app-name
# 4. 通知
echo "密钥 $SECRET_NAME 轮换完成"
定期轮换策略
# rotation-policy.yaml
rotation:
database_passwords:
frequency: "30d"
auto_rotate: true
notification:
- email: "admin@example.com"
- slack: "#security-alerts"
api_keys:
frequency: "90d"
auto_rotate: false
approval_required: true
tls_certificates:
frequency: "365d"
auto_rotate: true
renewal_before: "30d"
配置管理
环境变量管理
# .env文件(不要提交到Git)
# 使用direnv或dotenv加载
export DB_HOST=localhost
export DB_PORT=5432
export DB_USERNAME=app_user
export DB_PASSWORD=secretpassword
export API_KEY=your-api-key
外部配置存储
# configmap-with-secrets.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQ=
API_KEY: c2VjcmV0LWFwaS1rZXk=
审计和监控
访问日志
# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ""
resources: ["secrets"]
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
verbs: ["create", "update", "patch", "delete"]
监控告警
# prometheus-rules.yaml
groups:
- name: secrets-alerts
rules:
- alert: SecretAccessDenied
expr: kubernetes_api_server_audit_event{verb="get",resource="secrets",code="403"} > 0
for: 5m
labels:
severity: warning
annotations:
summary: "密钥访问被拒绝"
description: "检测到密钥访问被拒绝事件"
- alert: SecretRotationOverdue
expr: time() - secret_last_rotation_timestamp > 30 * 24 * 3600
labels:
severity: warning
annotations:
summary: "密钥轮换过期"
description: "密钥 {{ $labels.secret }} 超过30天未轮换"
安全最佳实践
- 不要硬编码: 永远不要在代码中硬编码密钥
- 使用密钥管理服务: 使用专业的密钥管理服务
- 定期轮换: 定期更换密钥和密码
- 最小权限: 只授予必要的访问权限
- 审计日志: 记录所有密钥访问
- 加密传输: 确保密钥在传输过程中加密
- 安全删除: 安全删除不再使用的密钥