密钥管理 secrets-management

本技能涉及使用HashiCorp Vault、AWS Secrets Manager和Kubernetes Secrets等工具实现密钥管理系统,以安全地存储、轮换和审计敏感凭证和密钥。

云安全 0 次安装 0 次浏览 更新于 3/4/2026

密钥管理

概述

部署和配置安全的密钥管理系统,以存储、轮换和审计对敏感凭证、API密钥和证书的访问权限。

何时使用

  • 数据库凭证管理
  • API密钥和令牌存储
  • 证书管理
  • SSH密钥分发
  • 凭证轮换自动化
  • 审计和合规日志记录
  • 多环境密钥
  • 加密密钥管理

实施示例

1. HashiCorp Vault 设置

# vault-config.hcl
storage "raft" {
  path    = "/vault/data"
  node_id = "node1"
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/vault/config/vault.crt"
  tls_key_file  = "/vault/config/vault.key"
}

api_addr     = "https://0.0.0.0:8200"
cluster_addr = "https://0.0.0.0:8201"

ui = true

2. Vault Kubernetes 集成

# vault-kubernetes.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-auth
  namespace: vault

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: vault-auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
  - kind: ServiceAccount
    name: vault-auth
    namespace: vault

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: vault
  namespace: vault
spec:
  replicas: 3
  serviceName: vault
  selector:
    matchLabels:
      app: vault
  template:
    metadata:
      labels:
        app: vault
    spec:
      serviceAccountName: vault-auth
      containers:
        - name: vault
          image: vault:1.15.0
          args:
            - "server"
            - "-config=/vault/config/vault.hcl"
          ports:
            - containerPort: 8200
              name: api
            - containerPort: 8201
              name: cluster
          securityContext:
            runAsNonRoot: true
            runAsUser: 100
            capabilities:
              add:
                - IPC_LOCK
          env:
            - name: VAULT_CLUSTER_ADDR
              value: "https://127.0.0.1:8201"
            - name: VAULT_API_ADDR
              value: "https://127.0.0.1:8200"
            - name: VAULT_SKIP_VERIFY
              value: "false"
          volumeMounts:
            - name: vault-config
              mountPath: /vault/config
            - name: vault-data
              mountPath: /vault/data
            - name: vault-logs
              mountPath: /vault/logs
          livenessProbe:
            httpGet:
              path: /v1/sys/health
              port: 8200
              scheme: HTTPS
            initialDelaySeconds: 60
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /v1/sys/health
              port: 8200
              scheme: HTTPS
            initialDelaySeconds: 30
            periodSeconds: 5
      volumes:
        - name: vault-config
          configMap:
            name: vault-config
        - name: vault-logs
          emptyDir: {}
  volumeClaimTemplates:
    - metadata:
        name: vault-data
      spec:
        accessModes: [ReadWriteOnce]
        resources:
          requests:
            storage: 10Gi

---
apiVersion: v1
kind: Service
metadata:
  name: vault
  namespace: vault
spec:
  clusterIP: None
  ports:
    - port: 8200
      targetPort: 8200
      name: api
    - port: 8201
      targetPort: 8201
      name: cluster
  selector:
    app: vault

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: vault-config
  namespace: vault
data:
  vault.hcl: |
    storage "raft" {
      path    = "/vault/data"
      node_id = "node1"
    }

    listener "tcp" {
      address       = "0.0.0.0:8200"
      tls_cert_file = "/vault/config/vault.crt"
      tls_key_file  = "/vault/config/vault.key"
    }

    api_addr     = "https://vault:8200"
    cluster_addr = "https://vault:8201"
    ui = true

3. Vault 密钥配置

#!/bin/bash
# vault-setup.sh - 为应用程序配置Vault

set -euo pipefail

VAULT_ADDR="https://vault:8200"
VAULT_TOKEN="${VAULT_TOKEN}"

export VAULT_ADDR
export VAULT_TOKEN

echo "Setting up Vault secrets..."

# 启用密钥引擎
vault secrets enable -version=2 kv
vault secrets enable -path=database database

# 创建数据库凭证
vault write database/config/mydb \
  plugin_name=postgresql-database-plugin \
  allowed_roles="readonly,readwrite" \
  connection_url="postgresql://{{username}}:{{password}}@postgres:5432/mydb" \
  username="vault_admin" \
  password="vault_password"

# 创建数据库角色
vault write database/roles/readonly \
  db_name=mydb \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \
  revocation_statements="DROP ROLE IF EXISTS \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# 创建API密钥
vault kv put secret/api/keys \
  github_token="ghp_xxxxxxxxxxx" \
  aws_access_key="AKIAIOSFODNN7EXAMPLE" \
  aws_secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  slack_webhook="https://hooks.slack.com/services/..."

# 创建TLS证书
vault write -f pki/root/generate/internal \
  common_name="my-root-ca" \
  ttl="87600h"

vault write pki/roles/my-domain \
  allowed_domains="*.myapp.com,myapp.com" \
  allow_subdomains=true \
  max_ttl="720h"

# 设置自动解封
vault write sys/seal/migrate/start \
  migrate_from_seal_type="shamir"

echo "Vault setup completed"

4. AWS Secrets Manager 配置

# aws-secrets-manager.py
import boto3
import json
from datetime import datetime

class SecretsManager:
    def __init__(self, region='us-east-1'):
        self.client = boto3.client('secretsmanager', region_name=region)

    def create_secret(self, name, secret_value, tags=None):
        """创建新密钥"""
        try:
            response = self.client.create_secret(
                Name=name,
                SecretString=json.dumps(secret_value),
                Tags=tags or []
            )
            return response['ARN']
        except Exception as e:
            print(f"Error creating secret: {e}")
            raise

    def get_secret(self, name):
        """检索密钥"""
        try:
            response = self.client.get_secret_value(SecretId=name)
            return json.loads(response['SecretString'])
        except Exception as e:
            print(f"Error retrieving secret: {e}")
            raise

    def update_secret(self, name, secret_value):
        """更新密钥"""
        try:
            response = self.client.update_secret(
                SecretId=name,
                SecretString=json.dumps(secret_value)
            )
            return response['ARN']
        except Exception as e:
            print(f"Error updating secret: {e}")
            raise

    def rotate_secret(self, name, rotation_rules):
        """启用自动轮换"""
        try:
            self.client.rotate_secret(
                SecretId=name,
                RotationRules=rotation_rules
            )
        except Exception as e:
            print(f"Error rotating secret: {e}")
            raise

    def list_secrets(self):
        """列出所有密钥"""
        try:
            response = self.client.list_secrets()
            return response['SecretList']
        except Exception as e:
            print(f"Error listing secrets: {e}")
            raise

    def delete_secret(self, name, recovery_days=30):
        """删除密钥并设置恢复期"""
        try:
            response = self.client.delete_secret(
                SecretId=name,
                RecoveryWindowInDays=recovery_days
            )
            return response
        except Exception as e:
            print(f"Error deleting secret: {e}")
            raise

# 使用方法
if __name__ == '__main__':
    manager = SecretsManager()

    # 创建数据库凭证密钥
    db_creds = {
        'username': 'admin',
        'password': 'SecurePassword123!',
        'host': 'postgres.example.com',
        'port': 5432,
        'dbname': 'myapp'
    }

    secret_arn = manager.create_secret(
        'prod/database/credentials',
        db_creds,
        tags=[
            {'Key': 'Environment', 'Value': 'production'},
            {'Key': 'Service', 'Value': 'myapp'}
        ]
    )

    print(f"Secret created: {secret_arn}")

    # 设置轮换
    manager.rotate_secret(
        'prod/database/credentials',
        {'AutomaticallyAfterDays': 30}
    )

    # 检索密钥
    retrieved = manager.get_secret('prod/database/credentials')
    print(f"Retrieved secret: {retrieved}")

5. Kubernetes 密钥

# kubernetes-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-credentials
  namespace: production
type: Opaque
stringData:
  database_url: "postgresql://user:pass@postgres:5432/myapp"
  api_key: "sk_live_xxxxxxxxxxxxxx"
  jwt_secret: "your-jwt-secret-key"

---
apiVersion: v1
kind: Secret
metadata:
  name: docker-registry
  namespace: production
type: kubernetes.io/dockercfg
data:
  .dockercfg: <base64-encoded-dockerconfig>

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      # 使用外部密钥操作符
      serviceAccountName: myapp
      containers:
        - name: app
          image: myapp:latest
          env:
            # 来自Kubernetes密钥
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-credentials
                  key: database_url
            # 来自挂载的密钥
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: app-credentials
                  key: api_key
          volumeMounts:
            - name: secrets
              mountPath: /app/secrets
              readOnly: true
      volumes:
        - name: secrets
          secret:
            secretName: app-credentials
            defaultMode: 0400

---
# 外部密钥操作符
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secret-store
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa

---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secret-store
    kind: SecretStore
  target:
    name: app-external-secret
    creationPolicy: Owner
  data:
    - secretKey: database_url
      remoteRef:
        key: prod/database/url
    - secretKey: api_key
      remoteRef:
        key: prod/api/key

最佳实践

✅ 要做

  • 定期轮换密钥
  • 使用强加密
  • 实施访问控制
  • 审计密钥访问
  • 使用托管服务
  • 实施密钥版本控制
  • 在传输中加密密钥
  • 为每个环境使用单独的密钥

❌ 不要做

  • 在代码中存储密钥
  • 使用弱加密
  • 通过电子邮件/聊天共享密钥
  • 将密钥提交到版本控制
  • 使用单个主密码
  • 日志记录密钥值
  • 硬编码凭证
  • 禁用轮换

资源