凭证配置:环境变量、AWS 配置文件与 IAM 角色
说实话,我刚开始用 AWS SDK 那会儿,最头疼的就是“到底该在哪设凭证”。环境变量?配置文件?还是直接写在代码里?
后来被同事提醒了一句——永远别把 Access Key 硬编码。从那以后,我才认真研究起凭证配置的几种正规姿势。
Secrets Manager SDK(底层就是 boto3)获取凭证有一套固定的查找顺序。理解这个顺序,你就知道该把密钥放在哪。我把它画成了下面的流程,帮你一眼看明白。
1. 环境变量:最简单,也最容易翻车
我个人习惯在本地开发时用环境变量——因为改起来最快。你只要导出两个变量:
export AWS_ACCESS_KEY_ID=AKIDEXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY
然后你的 boto3 客户端就能直接工作。SDK 内部会先检查 os.environ,找到就用。
.bashrc 或者项目根目录放一个 .env 文件(记得加到 .gitignore 里)。但注意,环境变量对 export 的 session 生效,重启终端就没了。我吃过一次亏——调试到一半切了个 tab,环境变量没带过来,报了个 AccessDenied,愣是查了半天。不过,环境变量也有个小坑:如果你同时配了临时凭证(AWS_SESSION_),必须三个一起设,缺一个会报失效。还有,别把生产环境的 Key 设到全局变量里——一旦不小心被日志打印出来,安全风险很大。
2. AWS 配置文件:项目级的推荐姿势
我在团队里一直推荐用配置文件。它比环境变量更结构化,而且支持多个 profile。你可以在 ~/.aws/credentials 里这样写:
[default]
aws_access_key_id = AKIDEXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY
[production]
aws_access_key_id = AKIDPROD
aws_secret_access_key = ProDSecretExampleKey123
然后在 ~/.aws/config 里配 region 和 output 格式:
[default]
region = us-east-1
output = json
[profile production]
region = ap-northeast-1
output = json
调用时通过 profile_name 指定:
import boto3
session = boto3.Session(profile_name='production')
client = session.client('secretsmanager')
profile 前缀,credentials 文件里不加。这是一个非常容易忘记的细节——我曾经就因为配置文件和凭证文件里的 profile 名称不一致,折腾了半小时。3. IAM 角色:生产环境的标准答案
如果你把应用部署到 EC2、ECS 或者 Lambda 上,千万不要再手动塞 Key 了。用 IAM 角色。给计算资源绑定一个角色,SDK 会自动从实例元数据服务(IMDS)获取临时凭证。
代码里什么都不用写:
import boto3
# 只要实例绑定了 IAM 角色,下面这句话自动找到凭证
client = boto3.client('secretsmanager')
region_name = 'ap-southeast-1' # 通常从实例 metadata 拿到
IAM 角色背后是 AWS STS 服务颁发的短期凭证,默认有效期 6 小时,SDK 会自动续期。我在一次生产故障复盘里发现,之前有人把长期 Access Key 写死在容器环境变量里,半年后 Key 泄露导致账单爆增。换用 IAM 角色后,这个问题再也没出现过。
三种方式的对比
| 方式 | 适用场景 | 安全等级 | 推荐指数 |
|---|---|---|---|
| 环境变量 | 本地开发、快速测试 | ⭐ 较低(可能泄露到日志) | ⭐⭐⭐ |
| 配置文件 | 个人项目、单个应用 | ⭐⭐ 中等(文件权限需设好) | ⭐⭐⭐⭐ |
| IAM 角色 | 生产部署(EC2/ECS/Lambda) | ⭐⭐⭐⭐⭐ 高(临时凭证 + 自动轮转) | ⭐⭐⭐⭐⭐ |
另外还有一个细节:如果你同时配了环境变量和配置文件,环境变量优先级更高。所以调试时你可以用环境变量覆盖配置文件里的 Key,非常方便。
一个典型的初始化示例
把上面三种方式整合到一个函数里,保证在任何环境都能用:
import boto3
import os
def get_secrets_client(profile_name=None, region_name='ap-northeast-1'):
"""安全地创建 Secrets Manager 客户端"""
# 1. 优先用环境变量
if os.environ.get('AWS_ACCESS_KEY_ID'):
return boto3.client('secretsmanager', region_name=region_name)
# 2. 其次用 profile
if profile_name:
session = boto3.Session(profile_name=profile_name)
return session.client('secretsmanager', region_name=region_name)
# 3. 最后走默认链(包含 IAM 角色)
return boto3.client('secretsmanager', region_name=region_name)
这个模式我在好几个项目里用过。本地跑单元测试就设个环境变量,CI/CD 里用 profile,上生产直接靠 IAM 角色——代码一行不用改。
避坑指南
- 永远别硬编码——Access Key 如果在代码库里提交了,即使马上删掉,它仍可能存在于 Git 历史中。用
git-secrets或者truffleHog扫描一下。 - 临时凭证过期处理:如果你手动调用 STS 拿临时凭证,记得存到
AWS_SESSION_里。SDK 遇到 401 会尝试刷新,但不是所有操作都支持,最好在代码里加个重试。 - 配置文件权限:
~/.aws/credentials文件应该设成600权限。我见过有人把配置文件的权限设成 644,结果被共享服务器上的其他用户读到——直接拉取了一把 Key。 - 多账户场景:可以使用
AWS_PROFILE环境变量来指定默认 profile,不用每次都传profile_name。不过记得检查你当前 terminal 是否不小心设了这个变量,容易混淆。
好了,凭证配置这块就这么多。我的建议是:本地开发先用环境变量试水,项目稳定后切到配置文件,上生产一定用 IAM 角色。你想想看,这样既灵活又安全,是不是挺简单的?