AWS Secrets Manager:创建、读取、轮换 Secrets,IAM 权限配置
说实话,在我刚接触云安全那会儿,管理敏感信息是个挺头疼的事。代码里硬编码密钥?那是新手才干的。环境变量?稍微好点,但轮换起来麻烦得要命。直到 AWS Secrets Manager 出现,我才觉得这事儿终于有了正解。
这章咱们就聊聊怎么创建、读取和轮换 Secrets,以及怎么配好 IAM 权限。嗯,这些都是你日常用得最多的操作。
创建 Secret:从控制台到 CLI
创建 Secret 其实很简单。我个人习惯先用控制台走一遍,然后再用 CLI 或 SDK 自动化。控制台的向导很友好,你只需要选好密钥类型(明文还是 JSON),设置好自动轮换周期就行。
看看 CLI 怎么做:
# 创建一个明文 Secret
aws secretsmanager create-secret \
--name MyDatabaseSecret \
--secret-string '{"username":"admin","password":"P@ssw0rd!"}' \
--region us-east-1
# 创建一个 JSON 格式的 Secret(更推荐)
aws secretsmanager create-secret \
--name MyApiKeySecret \
--secret-string '{"":"abc123xyz789"}' \
--kms-key-id alias/my-custom-key \
--description " for external service"
我在项目中遇到过一个问题:创建 Secret 时没指定 KMS 密钥。结果默认用了 AWS 托管密钥,后来审计发现不符合合规要求。所以记住,如果公司有加密策略,最好用自定义 KMS 密钥。
prod/app1/db/password。这样后续管理和权限控制都方便。
读取 Secret:应用程序的正确姿势
读 Secret 的核心操作就一个 API:GetSecretValue。但你想想看,如果每次请求都去调用 AWS API,延迟和成本都受不了。所以最佳实践是缓存。
这是我在生产环境用的代码模式:
import boto3
from botocore.exceptions import ClientError
def get_secret(secret_name, region="us-east-1"):
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region
)
try:
response = client.get_secret_value(SecretId=secret_name)
return response['SecretString']
except ClientError as e:
if e.response['Error']['Code'] == 'ResourceNotFoundException':
print(f"Secret {secret_name} not found")
elif e.response['Error']['Code'] == 'AccessDeniedException':
print(f"Access denied to secret {secret_name}")
else:
raise e
这里有个坑:我见过不少团队直接在生产环境每次请求都读取 Secret。其实你应该缓存到本地内存,并设置一个合理的过期时间(比如轮换间隔的一半)。
自动轮换 Secrets:安全基石
为什么要轮换?说白了,如果密钥泄露了,轮换能把损失降到最低。AWS Secrets Manager 支持自动轮换,但需要你配置一个 Lambda 函数。
轮换流程大概是这样的:
- 创建新版本:Lambda 生成新密码并标记为
AWSPENDING - 测试新版本:验证新密码能正常工作(比如连数据库)
- 切换:把新密码标记为
AWSCURRENT,旧密码变成AWSPREVIOUS - 清理:把
AWSPENDING状态移除
我自己写了一个轮换 Lambda,用 RDS 作为示例:
import boto3
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
secret_id = event['SecretId']
client_ = event['ClientRequestToken']
step = event['Step']
secrets_client = boto3.client('secretsmanager')
try:
metadata = secrets_client.describe_secret(SecretId=secret_id)
if 'RotationEnabled' not in metadata:
raise ValueError("Secret not configured for rotation")
versions = metadata['VersionIdsToStages']
if client_ not in versions:
raise ValueError("Invalid client ")
if metadata['RotationRules']['AutomaticallyAfterDays'] is None:
raise ValueError("Rotation interval not set")
if step == 'createSecret':
create_secret(secrets_client, secret_id, client_)
elif step == 'setSecret':
set_secret(secrets_client, secret_id, client_)
elif step == 'testSecret':
test_secret(secrets_client, secret_id, client_)
elif step == 'finishSecret':
finish_secret(secrets_client, secret_id, client_)
else:
raise ValueError(f"Unknown step: {step}")
except Exception as e:
logger.error(f"Rotation failed: {str(e)}")
raise e
我建议轮换周期不要设太长。30天是比较平衡的选择。我见过有人设90天,结果密钥泄露了还不知道。另外,如果数据库压力大,可以安排在凌晨执行轮换。
IAM 权限配置:最小权限原则
权限配置是 Secrets Manager 安全的核心。你看,如果每个开发者都能访问所有 Secret,那跟没加密差不多。
先看看基础策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/app1/*"
}
]
}
这个策略只允许读取 prod/app1/ 路径下的 Secret。我建议你按环境(dev/staging/prod)和应用维度来做资源隔离。
还有一个容易被忽略的点:条件键。比如你可以限制只能从特定的 VPC 访问:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "secretsmanager:GetSecretValue",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:SourceVpc": "vpc-0abc123def456"
}
}
}
]
}
为什么这样做?如果你的应用跑在 EC2 上,这样就算有人拿到了访问密钥,也必须通过你的 VPC 才能读 Secret。安全又加了一层。
| 权限场景 | 建议最小操作 | 资源范围 |
|---|---|---|
| 应用读取 | GetSecretValue |
特定路径下的 Secret |
| 管理员创建/更新 | CreateSecret、PutSecretValue、UpdateSecret |
按应用隔离 |
| 轮换 Lambda | GetSecretValue、PutSecretValue、UpdateSecretVersionStage |
特定 Secret ARN |
| 审计 | DescribeSecret、ListSecrets |
全局,但只读 |
实战建议
给你分享几个我在项目中积累的经验:
- Secret 版本管理:轮换时不要手动删除旧版本,AWS 会自动保留最近的 100 个版本。万一新密钥出问题,还能回滚。
- 监控告警:用 CloudWatch 监控
GetSecretValue调用的失败次数,超出阈值就告警。这能帮你发现权限问题或攻击行为。 - 标签:给每个 Secret 打上标签,比如
Environment=production、Owner=platform-team。这样后期查询和成本分析都方便。
好了,这一章的内容就到这。记住,Secrets Manager 不是银弹,但它能帮你把秘密管理这件事变得可控、可审计、可自动化。下一章咱们聊聊怎么把 Secrets 和 CI/CD 集成,让密钥在流水线里安全流转。