秘密的管理艺术:Secrets Manager 基础与 IAM 权限模型
搞安全的人都知道——密码、、数据库凭证这些敏感信息,不能硬编码在代码里。但现实中我见过不少团队把密钥写在配置文件中,甚至提交到 Git 仓库。嗯,这就像把家门钥匙挂在门上。AWS Secrets Manager 就是帮你管好这些“钥匙”的服务,自动轮换、细粒度授权,用起来很顺手。
创建秘密:从控制台到 CLI
创建秘密有两种主流方式:控制台点点点,或者 CLI 一把梭。我个人习惯用 CLI,因为可重复、可自动化。先看一个最基本的例子:
aws secretsmanager create-secret \
--name MyDBSecret \
--description "RDS primary credentials" \
--secret-string '{"username":"admin","password":"P@ssw0rd123"}' \
--tags Key=Environment,Value=Production
这里要注意几个点:
- secret-string 可以是任意字符串,但推荐用 JSON 结构,方便后续解析。
- --tags 不是可选项,我建议生产环境必打标签,后面做成本分摊和权限控制都依赖它。
- 秘密名称(
MyDBSecret)一旦创建就不可修改,只能删除重建。起名要规范。
控制台创建的步骤也差不多,填好键值对,AWS 还提供“自动生成密码”的功能,长度、特殊字符都能定制。我曾经帮一个客户迁移时,他们手动设了 100 位随机字符串——结果程序连接超时,因为密码太长解析慢。经验是 32-64 位,够用且稳定。
存储与加密:KMS 自动保护
秘密创建后,Secrets Manager 会用 AWS KMS 自动加密。默认使用服务自带的 aws/secretsmanager 托管密钥,不需要额外付费。但如果你有合规要求(比如必须使用自己的 CMK),在创建时可以指定:
aws secretsmanager create-secret \
--name MyDBSecret \
--kms-key-id arn:aws:kms:us-east-1:123456789012:key/xxxx-xxxx-xxxx-xxxx \
--secret-string '{"username":"admin","password":"P@ssw0rd123"}'
秘密的存储本身不额外收费,但 API 调用、存储大小和轮换次数都会产生费用。我一般建议把大型连接字符串拆成多个小秘密,按模块分类。
自动轮换:Lambda 驱动,零停机
轮换是 Secrets Manager 的杀手锏。它通过 Lambda 函数自动更新密码,期间服务不停顿。工作原理大致分两步:
- 创建轮换 Lambda —— 推荐直接用 AWS 提供的轮换模板(RDS、Redshift、DocDB 等),也可以自己写。
- 配置轮换周期 —— 在秘密属性中设置
RotationSchedule,比如每 30 天轮换一次。
这里有一个坑:默认的 Lambda 执行角色需要最小权限。我曾在项目中见到有人给 Lambda 绑了 AdministratorAccess——不推荐。按最小权限原则,权限应该只包括:
secretsmanager:GetSecretValue(读取当前秘密)secretsmanager:PutSecretValue(写入新版本)secretsmanager:UpdateSecretVersionStage(管理版本阶段)- 目标服务的修改密码权限(比如
rds:ModifyDBInstance)
--rotation-rules AutomaticallyRotateAfterDays=90 测试一轮,确认 Lambda 日志没有报错,再改成生产周期。千万别一上来就设 7 天轮换——如果函数有 bug,一周后全体数据库密码都乱了。
IAM 权限模型:谁可以看,谁可以改
Secrets Manager 的权限控制基于 IAM 策略,分成两个维度:
- 管理操作:
CreateSecret、DeleteSecret、PutSecretValue - 读取操作:
GetSecretValue、DescribeSecret
大部分场景下,只有管理员才需要写权限,普通应用只需要读。下面是一个典型的最小权限策略,只允许某个 EC2 角色读取特定秘密:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:MyDBSecret-*"
}
]
}
| 操作 | IAM Action | 最小资源 | 典型场景 |
|---|---|---|---|
| 创建秘密 | secretsmanager:CreateSecret | * | 管理员创建新凭证 |
| 读取秘密 | secretsmanager:GetSecretValue | 特定秘密 ARN | 应用启动时获取数据库密码 |
| 修改秘密 | secretsmanager:PutSecretValue | 特定秘密 ARN | 手动更新凭证 |
| 启用轮换 | secretsmanager:RotateSecret | 特定秘密 ARN | 配置自动轮换 |
| 删除秘密 | secretsmanager:DeleteSecret | 特定秘密 ARN | 清理废弃秘密 |
这里要特别强调一个细节:GetSecretValue 返回明文密码,所以该权限一定要收敛。我习惯在策略中加上条件,比如只允许来自 VPC 内的请求:
"Condition": {
"StringEquals": {
"aws:SourceVpce": "vpce-xxxxxxxx"
}
}
secretsmanager:* 权限。我把这句贴在团队 wiki 页面上,谁违反谁请喝咖啡。
避坑指南:我踩过的三个雷
- 跨区域访问秘密: 秘密是区域资源,不能跨 region 读取。如果需要,只能通过同步工具(如
aws secretsmanager replicate-secret)复制到其他区域。 - 版本管理混乱: Secrets Manager 自动管理版本(AWSCURRENT、AWSPREVIOUS)。如果你手动多次更新又不指定阶段,会堆积废弃版本,产生存储费用。记得定期清理。
- Lambda 轮换超时: 默认 Lambda 超时 3 秒,但修改数据库密码可能需要几秒到几十秒。我遇到过超时报错导致轮换失败。建议把 Lambda 超时设为 30 秒以上。
嗯,以上就是 Secrets Manager 的核心基础。创建、存储、轮换、权限管理——这四步走稳了,后面才能放心地把 Secrets 接入 CloudTrail 做审计可视化。下节课我们直接上手实操,看看怎么用 SDK 获取秘密并记录到 CloudTrail。