← 返回首页
🔧

密钥管理:安全存储敏感信息

📂 devops ⏱ 3 min 520 words

密钥管理:安全存储敏感信息

什么是密钥管理

密钥管理是指安全地存储、访问和轮换敏感信息(如密码、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天未轮换"

安全最佳实践

  1. 不要硬编码: 永远不要在代码中硬编码密钥
  2. 使用密钥管理服务: 使用专业的密钥管理服务
  3. 定期轮换: 定期更换密钥和密码
  4. 最小权限: 只授予必要的访问权限
  5. 审计日志: 记录所有密钥访问
  6. 加密传输: 确保密钥在传输过程中加密
  7. 安全删除: 安全删除不再使用的密钥