部署与运维

服务器运维笔记:密钥与敏感信息管理

密钥泄露是运维事故中后果最严重的类型之一。本文系统梳理服务器环境中密钥与敏感信息的全生命周期管理方案,涵盖环境变量、Vault、容器密钥、Git 安全、密钥轮换、配置中心、审计合规等核心话题,附带可落地的命令与配置示例。

密钥泄露是运维事故中后果最严重的类型之一。本文系统梳理服务器环境中密钥与敏感信息的全生命周期管理方案,涵盖环境变量、Vault、容器密钥、Git 安全、密钥轮换、配置中心、审计合规等核心话题,附带可落地的命令与配置示例。


敏感信息管理概述

什么是敏感信息

在服务器运维语境下,敏感信息包括但不限于:

类别 示例
认证凭据 数据库密码、API Key、OAuth Secret
加密材料 TLS 证书私钥、SSH 私钥、GPG 私钥
连接字符串 Redis URL、MQTT Broker 地址含密码
配置数据 内网 IP 段、第三方服务 Account ID
业务数据 用户 PII、支付密钥、加密盐值

核心原则

  1. 最小暴露:仅在需要的组件、需要的时刻可见
  2. 静态加密:存储时必须加密(at-rest encryption)
  3. 传输加密:传输时必须走 TLS(in-transit encryption)
  4. 审计追踪:每一次访问和变更必须有日志
  5. 定期轮换:密钥有生命周期,到期必须更换
  6. 零信任:不因“内网”而降低安全标准

环境变量管理

.env 文件基础

.env 是最常见也最基础的密钥管理方式。适用于开发和小规模部署。

plaintext9 行
# .env 文件示例
DB_HOST=10.0.1.50
DB_PORT=5432
DB_USER=app_rw
DB_PASSWORD=S3cur3P@ssw0rd!
REDIS_URL=redis://:r3d1s_s3cr3t@10.0.1.60:6379/0
JWT_SECRET=eyJhbGciOiJIUzI1NiJ9.dGVzdA
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

.gitignore 必须包含:

plaintext3 行
.env
.env.*
!.env.example

direnv —— 目录级环境变量管理

direnv 根据当前目录自动加载/卸载环境变量,比手动 source 更安全。

plaintext7 行
# 安装
sudo apt install direnv        # Debian/Ubuntu
brew install direnv             # macOS

# 在 shell 配置中 hook(以 bash 为例)
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc

项目目录下创建 .envrc:

plaintext6 行
# .envrc
dotenv_if_exists .env

# 也可以直接设置
export DB_PASSWORD="S3cur3P@ssw0rd!"
export APP_ENV="production"
plaintext11 行
# 激活
direnv allow .

# 验证
echo $DB_PASSWORD
# 输出: S3cur3P@ssw0rd!

# 离开目录后自动卸载
cd ..
echo $DB_PASSWORD
# 输出: (空)

安全增强 —— 使用 age 加密 .envrc:

plaintext12 行
# 安装 age
go install filippo.io/age/cmd/...@latest

# 生成密钥
age-keygen -o ~/.age/key.txt

# 加密
age -r age1xxxxxxxxx -o .envrc.age .envrc

# .envrc 中解密加载
# .envrc
age -d -i ~/.age/key.txt .envrc.age | dotenv_if_exists /dev/stdin

HashiCorp Vault

Vault 是企业级密钥管理的事实标准,提供集中式密钥存储、动态密钥生成、自动轮换和完整审计。

安装与启动

plaintext9 行
# 添加 GPG key 和仓库(Debian/Ubuntu)
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install vault

# 开发模式启动(仅用于测试)
vault server -dev -dev-root-token-id=root

# 生产模式配置文件 /etc/vault.d/vault.hcl

生产环境配置 vault.hcl:

plaintext20 行
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-node-1"
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/etc/vault.d/tls/server.crt"
  tls_key_file  = "/etc/vault.d/tls/server.key"
}

api_addr     = "https://vault.internal.example.com:8200"
cluster_addr = "https://vault.internal.example.com:8201"

telemetry {
  prometheus_retention_time = "30s"
  disable_hostname          = true
}

ui = true
plaintext13 行
# 启动服务
sudo systemctl enable vault
sudo systemctl start vault

# 初始化(首次)
export VAULT_ADDR="https://vault.internal.example.com:8200"
vault operator init -key-shares=5 -key-threshold=3
#  输出的 5 个 Unseal Key 和 Initial Root Token 必须安全分发给不同的人

# 解封
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>

Secret Engine

KV v2 —— 通用密钥存储:

plaintext18 行
# 启用 KV v2 引擎
vault secrets enable -path=secret kv-v2

# 写入密钥
vault kv put secret/myapp/db \
  host="10.0.1.50" \
  port="5432" \
  username="app_rw" \
  password="S3cur3P@ssw0rd!"

# 读取
vault kv get secret/myapp/db
vault kv get -field=password secret/myapp/db

# 版本管理
vault kv get -version=2 secret/myapp/db
vault kv rollback -version=1 secret/myapp/db
vault kv metadata delete secret/myapp/db

Transit Engine —— 加密即服务:

plaintext13 行
# 启用
vault secrets enable transit

# 创建加密密钥
vault write -f transit/keys/myapp-key

# 加密
vault write transit/encrypt/myapp-key \
  plaintext=$(base64 <<< "敏感数据需要加密存储")

# 解密
vault write transit/decrypt/myapp-key \
  ciphertext="vault:v1:xxxxxx"

认证方法

plaintext22 行
# AppRole(推荐用于机器对机器认证)
vault auth enable approle

# 创建角色
vault write auth/approle/role/myapp \
  secret_id_ttl=10m \
  token_num_uses=10 \
  token_ttl=20m \
  token_max_ttl=30m \
  secret_id_num_uses=40 \
  policies="myapp-policy"

# 获取 Role ID
vault read auth/approle/role/myapp/role-id

# 获取 Secret ID
vault write -f auth/approle/role/myapp/secret-id

# 使用 AppRole 登录
vault write auth/approle/login \
  role_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  secret_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Kubernetes 认证(K8s Pod 直接认证):

plaintext6 行
# 启用
vault auth enable kubernetes

# 配置(在 Vault Pod 中执行)
vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc:443"

策略(Policy)

plaintext21 行
# myapp-policy.hcl
path "secret/data/myapp/*" {
  capabilities = ["read", "list"]
}

path "secret/data/myapp/db" {
  capabilities = ["read", "list", "create", "update"]
}

path "transit/encrypt/myapp-key" {
  capabilities = ["update"]
}

path "transit/decrypt/myapp-key" {
  capabilities = ["update"]
}

# 禁止访问其他路径
path "secret/data/*" {
  capabilities = ["deny"]
}
plaintext1 行
vault policy write myapp-policy myapp-policy.hcl

动态密钥(Dynamic Secrets)

Vault 动态凭据按租约管理,需核对后端生成、续租、过期与撤销语义。应用用完凭据后仍要按租约策略处理。

PostgreSQL 动态密钥:

plaintext22 行
# 配置数据库连接
vault write database/config/my-postgres \
  plugin_name=postgresql-database-plugin \
  connection_url="postgresql://{{username}}:{{password}}@10.0.1.50:5432/mydb" \
  allowed_roles="readonly" \
  username="vault_admin" \
  password="vault_admin_password"

# 创建角色
vault write database/roles/readonly \
  db_name=my-postgres \
  creation_statements="CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";" \
  default_ttl="1h" \
  max_ttl="24h"

# 获取临时凭据
vault read database/creds/readonly
# 输出:
#   username: v-token-readonly-abc123
#   password: A1b2-C3d4-E5f6-...
#   ttl: 1h

Docker Secrets

Docker Swarm 内置密钥管理,密钥以 tmpfs 挂载到容器,不写入镜像层。

创建与使用

plaintext18 行
# 创建密钥
echo "S3cur3P@ssw0rd!" | docker secret create db_password -

# 从文件创建
docker secret create tls_cert /path/to/cert.pem

# 列出密钥
docker secret ls

# 在 service 中使用
docker service create \
  --name myapp \
  --secret db_password \
  --secret tls_cert \
  myapp:latest

# 容器内密钥挂载在 /run/secrets/
# 应用读取: cat /run/secrets/db_password

Docker Compose 集成

yaml18 行
# docker-compose.yml(Swarm 模式)
version: "3.8"

services:
  app:
    image: myapp:latest
    secrets:
      - db_password
      - api_key
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password
      API_KEY_FILE: /run/secrets/api_key

secrets:
  db_password:
    external: true
  api_key:
    external: true

非 Swarm 环境替代方案

yaml12 行
# docker-compose.yml(非 Swarm,使用 bind mount + tmpfs)
version: "3.8"

services:
  app:
    image: myapp:latest
    tmpfs:
      - /run/secrets
    volumes:
      - ./secrets/db_password.txt:/run/secrets/db_password:ro
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password

Kubernetes Secrets

原生 Secret

yaml11 行
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
  namespace: production
type: Opaque
stringData:
  DB_PASSWORD: "S3cur3P@ssw0rd!"
  API_KEY: "ak_xxxxxxxxxxxxxxxx"
  REDIS_URL: "redis://:p@ss@redis:6379/0"
plaintext4 行
# 创建
kubectl apply -f secret.yaml

# 使用方式 1:环境变量
plaintext6 行
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: myapp-secrets
        key: DB_PASSWORD
plaintext11 行
# 使用方式 2:Volume 挂载
volumes:
  - name: secret-volume
    secret:
      secretName: myapp-secrets
containers:
  - name: app
    volumeMounts:
      - name: secret-volume
        mountPath: /etc/secrets
        readOnly: true

加密静态数据(EncryptionConfiguration)

yaml12 行
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>
      - identity: {}
plaintext9 行
# 生成加密 key
head -c 32 /dev/urandom | base64

# 重启 API Server 应用配置
# 在 kube-apiserver 启动参数中添加:
# --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

# 加密已有的 Secrets
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

External Secrets Operator(ESO)

ESO 将外部密钥管理系统(Vault、AWS SM、Azure KV 等)与 K8s Secret 同步。

plaintext4 行
# 安装
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
  -n external-secrets --create-namespace
yaml18 行
# SecretStore 引用 Vault
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: production
spec:
  provider:
    vault:
      server: "https://vault.internal.example.com:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp"
          serviceAccountRef:
            name: "myapp-sa"
yaml23 行
# ExternalSecret 同步
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-external-secret
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: myapp-secrets
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: secret/myapp/db
        property: password
    - secretKey: API_KEY
      remoteRef:
        key: secret/myapp/api
        property: key

Git 安全:防止密钥泄露

git-secrets(AWS 开源)

plaintext21 行
# 安装
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets && sudo make install

# 在仓库中初始化
cd /path/to/repo
git secrets --install

# 注册 AWS 默认规则
git secrets --register-aws

# 自定义规则
git secrets --add 'password\s*=\s*.+'
git secrets --add 'PRIVATE KEY'
git secrets --add 'sk-[a-zA-Z0-9]{20,}'

# 扫描已有提交历史
git secrets --scan-history

# 扫描指定文件
git secrets --scan /path/to/file

BFG Repo-Cleaner —— 清理已泄露的密钥

当密钥已经提交到 Git 历史,必须彻底清除:

plaintext17 行
# 安装
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar

# 方法 1:删除包含特定文本的文件
java -jar bfg-1.14.0.jar --delete-files "*.env" repo.git

# 方法 2:替换敏感文本
echo "S3cur3P@ssw0rd!" > passwords.txt
java -jar bfg-1.14.0.jar --replace-text passwords.txt repo.git

# 清理引用
cd repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive

# 强制推送( 协调所有开发者重新 clone)
git push --force --all
git push --force --tags

pre-commit 钩子自动化

plaintext11 行
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

  - repo: https://github.com/awslabs/git-secrets
    rev: master
    hooks:
      - id: git-secrets
plaintext6 行
# 安装 pre-commit
pip install pre-commit
pre-commit install

# 手动运行
pre-commit run --all-files

Gitleaks CI 集成

yaml14 行
# .github/workflows/secret-scan.yml
name: Secret Scan
on: [push, pull_request]

jobs:
  gitleaks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

密钥轮换

为什么需要轮换

  • 降低泄露窗口期影响
  • 满足合规要求(PCI-DSS 要求至少 90 天)
  • 人员变动后清理权限
  • 应对零日漏洞

自动化轮换(Vault Agent Template)

plaintext30 行
# vault-agent-config.hcl
pid_file = "/var/run/vault/agent.pid"

vault {
  address = "https://vault.internal.example.com:8200"
}

auto_auth {
  method "approle" {
    mount_path = "auth/approle"
    config = {
      role_id_file_path                   = "/etc/vault/role-id"
      secret_id_file_path                 = "/etc/vault/secret-id"
      remove_secret_id_file_after_reading = true
    }
  }

  sink "file" {
    config = {
      path = "/var/run/vault/.vault-token"
    }
  }
}

template {
  source      = "/etc/vault/templates/db.ctmpl"
  destination = "/etc/app/secrets/db.json"
  perms       = 0600
  command     = "systemctl reload myapp"
}

Template 文件 db.ctmpl:

plaintext7 行
{{ with secret "database/creds/readonly" }}
{
  "username": "{{ .Data.username }}",
  "password": "{{ .Data.password }}",
  "ttl": "{{ .Data.ttl }}"
}
{{ end }}

凭据轮换与新连接验证

PostgreSQL 的 ALTER ROLE ... PASSWORD 更新该角色密码,VALID UNTIL 设置有效期,不提供同角色双密码重叠窗口。需要平滑过渡时,可把权限放在 NOLOGIN 组角色,创建新的 LOGIN 角色并授予同一组权限;还需核对对象所有权、默认权限与行级安全策略。ALTER ROLE 文档说明了密码和有效期的行为。

  1. 创建新登录角色并通过安全渠道设置凭据,按最小范围授予所需权限。
  2. 更新应用用户名与密码,滚动创建实例并强制建立新连接。
  3. 验证新角色实际执行代表性读写,检查连接池重连、失败率和旧会话余量。
  4. 确认切换完成后撤销旧角色登录能力,按业务窗口处理旧连接与角色归属。

已建立连接可能在密码更改后继续工作。因此日志中出现 connected 或滚动发布完成,都不足以证明新凭据可用。需要专门建立新连接进行验收。

Kubernetes 滚动更新策略:

plaintext16 行
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0    # 控制滚动替换数量,仍需就绪检查与容量余量
  template:
    spec:
      containers:
        - name: app
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: myapp-secrets
                  key: DB_PASSWORD

配置中心

Nacos

Nacos 支持配置管理和密钥管理,适用于微服务架构。

plaintext6 行
# Docker 部署
docker run -d --name nacos \
  -e MODE=standalone \
  -e NACOS_AUTH_ENABLE=true \
  -p 8848:8848 \
  nacos/nacos-server:v2.3.0
plaintext11 行
# 通过 API 创建加密配置
curl -X POST "http://nacos:8848/nacos/v1/cs/configs" \
  -d "dataId=app-secrets.yaml" \
  -d "group=PRODUCTION_GROUP" \
  -d "tenant=my-namespace" \
  -d "type=yaml" \
  --data-urlencode "content=db:
  password: 'ENC(S3cur3P@ssw0rd!)'
api:
  key: 'ENC(ak_xxxxxxxxxxxxxxxx)'" \
  -d "encryptedDataKey=encryption-key-id"

应用端配置解密(jasypt 集成):

plaintext13 行
# application.yml
spring:
  cloud:
    nacos:
      config:
        server-addr: nacos:8848
        namespace: my-namespace
        group: PRODUCTION_GROUP

jasypt:
  encryptor:
    password: ${JASYPT_PASSWORD}
    algorithm: PBEWithMD5AndDES

Apollo

plaintext5 行
# Apollo 配置(敏感信息用数据库加密存储)
# apollo-portal 的 application.properties
spring.datasource.url=jdbc:mysql://mysql:3306/ApolloPortalDB
spring.datasource.username=apollo
spring.datasource.password=${APOLLO_PORTAL_DB_PASSWORD}
plaintext3 行
// 应用端读取加密配置
@Value("${app.secret.api-key}")
private String apiKey;  // Apollo 自动解密

Consul Template

plaintext22 行
# consul-template-config.hcl
consul {
  address = "consul.internal.example.com:8500"
}

vault {
  address = "https://vault.internal.example.com:8200"
  renew_token = true
}

template {
  source      = "/etc/consul-template/templates/nginx.ctmpl"
  destination = "/etc/nginx/conf.d/app.conf"
  command     = "nginx -s reload"
}

template {
  source      = "/etc/consul-template/templates/app.ctmpl"
  destination = "/etc/app/config.json"
  perms       = 0600
  command     = "systemctl restart myapp"
}

审计与合规

Vault 审计日志

plaintext26 行
# 启用审计日志(至少启用两个后端以确保冗余)
vault audit enable file file_path=/var/log/vault/audit.log
vault audit enable syslog tag="vault"

# 审计日志示例输出(已脱敏)
{
  "type": "request",
  "auth": {
    "client_token": "hmac-sha256:xxxxx",
    "accessor": "hmac-sha256:xxxxx",
    "display_name": "approle-myapp",
    "policies": ["myapp-policy"]
  },
  "request": {
    "operation": "read",
    "path": "secret/data/myapp/db",
    "remote_address": "10.0.1.100"
  },
  "response": {
    "data": {
      "data": {
        "password": "hmac-sha256:xxxxx"
      }
    }
  }
}

合规检查清单

plaintext26 行
# 定期审计脚本
#!/bin/bash

echo "=== 密钥管理合规审计 $(date +%Y-%m-%d) ==="

# 1. 检查是否有硬编码密钥
echo "[1] 扫描代码中的硬编码密钥..."
gitleaks detect --source /path/to/repos --report-format json --report-path /tmp/gitleaks.json

# 2. 检查 Secret 是否加密存储
echo "[2] 检查 K8s Secret 加密状态..."
kubectl get secrets --all-namespaces -o json | jq '.items[] | select(.metadata.annotations["encryption"] == null) | .metadata.name'

# 3. 检查密钥年龄
echo "[3] 检查过期密钥..."
vault list secret/metadata/myapp/ | while read key; do
  created=$(vault kv metadata get -format=json "secret/myapp/$key" | jq '.data.versions | to_entries | last.value.created_time')
  echo "  $key: created $created"
done

# 4. 检查 TLS 证书过期
echo "[4] TLS 证书过期检查..."
for cert in /etc/ssl/certs/*.pem; do
  expiry=$(openssl x509 -enddate -noout -in "$cert" 2>/dev/null | cut -d= -f2)
  echo "  $cert: expires $expiry"
done

敏感信息分类分级

级别 定义 处理要求
L1 - 绝密 核心加密密钥、根证书 HSM 存储,双人审批,操作审计
L2 - 机密 数据库密码、API Key Vault 存储,自动轮换,访问审计
L3 - 私密 内部服务地址、配置参数 加密存储,权限控制
L4 - 内部 非敏感配置 标准访问控制

最佳实践与 SOP

密钥管理 SOP

plaintext11 行
┌─────────────────────────────────────────────────────┐
│               密钥生命周期 SOP                       │
├─────────────────────────────────────────────────────┤
│ 1. 生成 → 使用密码学安全随机数生成                     │
│ 2. 存储 → 加密存储于 Vault/Secret Manager             │
│ 3. 分发 → 通过安全通道分发,禁止明文传输               │
│ 4. 使用 → 最小权限原则,按需申请                       │
│ 5. 轮换 → 自动化定期轮换(建议 90 天以内)             │
│ 6. 撤销 → 泄露时立即撤销,触发应急流程                 │
│ 7. 审计 → 全程日志记录,定期审查                       │
└─────────────────────────────────────────────────────┘

应急响应流程

plaintext5 行
发现泄露 → 评估范围 → 立即撤销 → 生成新密钥
    ↓
更新所有引用 → 验证服务 → 监控异常 → 复盘改进
    ↓
根因分析 → 更新 SOP → 团队培训

应急命令速查:

plaintext16 行
# 立即撤销 Vault 中的密钥
vault kv metadata delete secret/myapp/leaked-key

# 撤销所有 Token
vault token revoke -prefix auth/approle/role/myapp

# 轮换数据库密码(PostgreSQL)
ALTER USER compromised_user PASSWORD 'new_password';

# 旋转 AWS Access Key
aws iam delete-access-key --user-name app-user --access-key-id AKIAXXXXXXXX
aws iam create-access-key --user-name app-user

# 使 K8s Secret 失效并重新创建
kubectl delete secret myapp-secrets -n production
kubectl apply -f new-secret.yaml

工具选型建议

场景 推荐方案 备选
单机/小团队 .env + direnv + git-secrets SOPS + age
Docker Swarm Docker Secrets Vault Agent
Kubernetes ESO + Vault Sealed Secrets
多云环境 Vault AWS SM / Azure KV
配置中心 Nacos(加密) Apollo / Consul
Git 防泄露 gitleaks + pre-commit git-secrets + truffleHog
证书管理 cert-manager + Vault PKI Let’s Encrypt

检查清单

  • 所有密钥存储于加密系统,禁止明文存放
  • .gitignore 已排除 .env、密钥文件、证书
  • Git 历史中无泄露的密钥(gitleaks 扫描通过)
  • 密钥有自动轮换机制,轮换周期 ≤ 90 天
  • 审计日志已启用,保留期 ≥ 180 天
  • 最小权限原则已落实,无超权访问
  • 应急流程已文档化并演练过
  • CI/CD 流水线包含密钥扫描步骤
  • 容器镜像中无密钥层(多阶段构建 + 扫描)
  • 传输层全链路 TLS,内部服务 mTLS

密钥轮换的撤销路径

每个密钥记录拥有者、用途、权限范围和轮换方式。验证新密钥可用后,还要验证旧密钥被撤销,以及备份、日志、缓存和离线任务中是否残留。

Secret 注入方式会影响更新何时生效:环境变量通常在进程创建时读取,文件挂载还需要应用重新加载。测试时创建新连接或执行真实鉴权,避免旧连接掩盖凭据切换失败。

← 返回文章