多云Secrets工具差异解析教程 - 第2节
AWS Secrets Manager 基础:核心概念与架构
说实话,刚接触 AWS Secrets Manager 那会儿,我第一反应是:这不就是个加密的键值对存储吗?用 DynamoDB 加个 KMS 也能凑合。但真的在生产环境跑起来,才发现它藏了不少细节。这一章我们先扎扎实实把基础打牢。
核心概念
先过一遍主要术语,后面操作才不会晕头转向。
| 概念 | 说明 |
|---|---|
| Secret | 一个机密数据对象,可以存数据库密码、、OAuth 等。最大 65,536 字节。 |
| Secret Value | 某个版本下的实际机密内容,可以是纯文本或 JSON 结构。 |
| Version / Stage | 每个 Secret 可以有多个版本,版本通过「Stage」标签管理(如 AWSCURRENT、AWSPREVIOUS)。 |
| Rotation | 自动轮换机制,Secrets Manager 可以按周期调 Lambda 函数更新密码。 |
| KMS Key | 加密用的对称密钥,默认使用 aws/secretsmanager 服务自带 CMK,也可以自己指定。 |
| Resource Policy | 类似 S3 Bucket Policy,直接挂到 Secret 上的权限策略,支持跨账号访问。 |
为啥要有「Stage」这层? 我曾经遇到一个场景:轮换期间新密码还在测试,旧密码需要继续可用。Secrets Manager 允许同时保留 AWSCURRENT 和 AWSPREVIOUS 两个版本,应用端在读取时直接指定 Stage,完全不用改代码。
架构拆解
来看一张简图,理解 Secrets Manager 在 AWS 环境里的位置和调用链。
嗯,这里有个点容易忽略:Secrets Manager 的读操作是有缓存的。SDK 默认会缓存 1 小时,如果你改了密码应用没读到,先查缓存时间,别急着怀疑代码。
我的习惯:生产环境用 secretsmanager:GetSecretValue 配合 IAM 条件键 secretsmanager:VersionStage 做精细控制,只允许取 AWSCURRENT 版本,避免应用意外读到旧密码。
基础操作:创建、读取、更新、删除
创建 Secret
我个人喜欢用 AWS CLI 做快速验证,控制台步骤多但更直观。先看 CLI 的创建方式:
# 创建简单的明文 Secret
aws secretsmanager create-secret \
--name dev/wordpress/db \
--description "WordPress 数据库密码" \
--secret-string "MyP@ssw0rd!2024" \
--kms-key-id alias/aws/secretsmanager
# 创建 JSON 结构的 Secret(推荐)
aws secretsmanager create-secret \
--name prod/ \
--secret-string '{"":"sk-xxxx","endpoint":"https://api.example.com"}' \
--tags Key=Environment,Value=prod
注意:不指定 --kms-key-id 的话,会用默认的 aws/secretsmanager 密钥,加密成本为零(不额外收费)。
我曾经踩过的坑:创建时 secret-string 超过 65KB 直接报错。如果你的凭证是几百 KB 的 JKS 或 PEM 文件,先压缩成 base64 再放到 secret-string 里,或者改用 --secret-binary 参数。
读取 Secret
读取是最频繁的操作。接口有 GetSecretValue 和 BatchGetSecretValue(批量获取,减少 API 调用次数)。
# 读取当前版本
aws secretsmanager get-secret-value \
--secret-id prod/ \
--version-stage AWSCURRENT
# 读取历史版本(回滚场景用)
aws secretsmanager get-secret-value \
--secret-id prod/ \
--version-id "a1b2c3d4-..."
返回的 JSON 里你会看到四个重要字段:SecretString(明文)、SecretBinary(二进制流)、VersionId(UUID)、VersionStages(当前 stage 列表)。
更新 Secret
更新不是直接在原值上改,而是 创建新版本。旧版本会打上 AWSPREVIOUS 标签保留。
# 更新 secret-string 内容
aws secretsmanager put-secret-value \
--secret-id prod/ \
--secret-string '{"":"sk-new","endpoint":"https://api.example.com"}' \
--version-stages AWSCURRENT
# 如果想强制覆盖某个 stage 的版本(比如把某个旧版本提升为当前版本)
aws secretsmanager update-secret-version-stage \
--secret-id prod/ \
--version-stage AWSCURRENT \
--remove-from-version-id "old-id" \
--move-to-version-id "new-id"
关于轮换的思考:手动 put-secret-value 不会触发轮换函数。如果你需要自动轮换数据库密码,得配置 Rotation Lambda。轮换策略有单用户和双用户两种,我遇到的大部分场景用单用户就够了——在 AWSCURRENT 更新前先创建临时凭证,应用无感知切换。
删除 Secret
删除分两步:先 计划删除(设置恢复窗口),超过窗口期才会真正删除。窗口期默认 30 天,最小 7 天。
# 计划删除,设置 7 天恢复窗口
aws secretsmanager delete-secret \
--secret-id dev/testing-key \
--recovery-window-in-days 7
# 如果你的 Secret 已经没用了,也不想留恢复机会,用 --force-delete-without-recovery
aws secretsmanager delete-secret \
--secret-id dev/testing-key \
--force-delete-without-recovery
千万别手抖用 force 模式! 我有个同事在测试环境误删了生产 Secret,还好 30 天窗口期救了一命。从那以后我养成了习惯:只在里程碑备份后才能用 force。
权限与审计
操作 Secrets Manager 必须要有 IAM 策略。举个例子,应用只需要读取,不要给它更新的权限:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/*",
"Condition": {
"StringEquals": {
"secretsmanager:VersionStage": "AWSCURRENT"
}
}
}
]
}
审计日志全部落在 CloudTrail 里,你可以通过 eventName 筛选:GetSecretValue、PutSecretValue、DeleteSecret 等。说实话,我每次排查问题第一件事就是查 CloudTrail,看看是谁在什么时间改了哪个 Secret。
总结一下操作清单
| 操作 | 对应 API | 注意事项 |
|---|---|---|
| 创建 | CreateSecret | 限定 KMS 权限,用 JSON 结构更易维护 |
| 读取 | GetSecretValue | 默认缓存 1 小时,可以指定版本 Stage |
| 更新 | PutSecretValue | 创建新版本,旧版本保留为 AWSPREVIOUS |
| 删除 | DeleteSecret | 必须设置恢复窗口,force 模式慎用 |
| 恢复 | RestoreSecret | 仅在计划删除窗口期内有效 |
一个小技巧:如果你的应用使用 Java 或 Python SDK,建议启用 Secrets Manager 缓存插件(比如 aws-secretsmanager-caching-java)。它内部做 LRU + 过期自动刷新,能把你 API 调用次数降到原来的十分之一,而且不会因为缓存读到脏数据。