访问密钥与配置

密钥管理这件事,说大不大,说小不小。我在实际项目里见过太多因为密钥泄露导致的事故了——有的直接把线上数据库给拖走了,有的被恶意刷了十几万的短信费。嗯,这章咱们就把密钥怎么拿、怎么存、怎么用,一次说清楚。

密钥的两种形态

Secrets Manager 的 SDK 接入,本质上就靠两样东西:访问密钥(Access Key)和配置环境。

类型说明使用场景
长期密钥Access Key ID + Secret Access Key本地开发、CI/CD、自建服务器
临时密钥STS 颁发的 生产环境、短期任务、跨账号授权
个人习惯:能不用长期密钥就别用。我一般只在本地开发时用长期密钥,生产环境一律走临时凭据。

密钥从哪里来?

你得先有一个 Secrets Manager 的访问身份。最常见的方式:

  1. 在云控制台创建一个子账号,赋予 SecretsManager 的读取权限
  2. 为该子账号生成 Access Key ID 和 Secret Access Key
  3. 把密钥下载到本地保存好——注意,下载后只有一次机会

讲究点的团队,会把密钥存在内部的密码管理工具里,比如 1Password、Keybase 或者 Vault。我遇到过一个项目,工程师直接把密钥写在代码里提交到 Git 仓库了……结果扫描工具报警,全组人连夜改密码。

千万别这么做:不要把密钥硬编码在源代码、配置文件或者环境变量的日志里。我曾经见过有人因为图方便,在 Dockerfile 里 ENV 直接写 Access Key,镜像一 push 到公共仓库——整个账号就裸奔了。

配置密钥的四种姿势

SDK 怎么知道用哪组密钥?官方 SDK 通常按优先级从高到低查找:

  • 环境变量:AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
  • 配置文件:~/.aws/credentials 或 ~/.aws/config
  • ECS 容器角色:容器或 ECS 任务绑定的 IAM 角色
  • 实例元数据:EC2 实例绑定的 IAM 角色

我个人最推荐用环境变量——简单、明确、不容易乱。看看代码怎么写:

// 设置环境变量(Linux/macOS)
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=cn-north-1

// 然后你的代码里直接创建客户端
const client = new SecretsManagerClient({ region: "cn-north-1" });

你想想看,这样是不是特别清晰?环境变量跟着进程走,不会污染全局。

配置文件详解

如果你用多套环境(比如开发、测试、生产),配置文件会更方便。位置在 ~/.aws/credentials,格式像下面这样:

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[dev]
aws_access_key_id = AKIAIDEV123EXAMPLE
aws_secret_access_key = DEVsecretKeyExample123

[prod]
aws_access_key_id = AKIAPROD456EXAMPLE
aws_secret_access_key = PRODsecretKeyExample789

使用时通过环境变量 AWS_PROFILE 切换:

export AWS_PROFILE=prod
node app.js   // 此时 SDK 自动读 prod 的密钥
我的经验:开发机上用 default 配置文件,CI 环境用环境变量注入,生产环境全部用 IAM 角色免密。这样能做到密钥零散落在人手里。

密钥安全存储与轮换

拿到了密钥,怎么存才安全?这里有一套我踩过坑总结出来的做法:

  1. 文件权限:配置文件必须 chmod 600,防止其他进程偷窥
  2. 不用版本控制:把 .aws/credentials 加到 .gitignore 里
  3. 定期轮换:设置密钥 90 天过期,用脚本自动生成新密钥并更新到 Secrets Manager 里
  4. 审计日志:开启 CloudTrail 记录谁调用了密钥相关的 API

我曾经接手过一个遗留系统,密钥三四年没换过,连当初是谁创建的都查不到了……后来我写了个自动轮换脚本,每个月跑一次,再也没出事。

核心逻辑图

下面我把密钥获取与使用流程画出来,你一眼就能看明白:

访问密钥配置与使用流程 密钥配置与 SDK 使用流程 密钥来源 控制台 / STS / IAM 角色 配置方式 环境变量 / 配置文件 / IAM SDK 初始化 自动查找密钥链 调用 Secrets Manager API GetSecretValue / ListSecrets 安全措施 加密存储 / 权限限制 / 审计 处理返回结果 解密 / 缓存 / 使用 💡 提示 SDK 会按 环境变量 → 配置文件 → IAM 角色 的顺序自动查找密钥 建议只在开发环境使用显式密钥,生产环境优先用临时凭据

常见配置陷阱

说几个我真实遇到过的问题,你写代码时能避开:

  • 区域不匹配:密钥有绑定区域,比如 cn-north-1 的密钥调用 us-east-1 的 Secrets Manager 会直接 403。记得在客户端构造时显式指定 region。
  • 权限过于宽泛:别给子账号配 SecretsManager:*,精确到资源 ARN 和操作。我在一个项目里发现有人配了通配符,结果一个测试账号能删掉所有密钥……
  • 缓存过期问题:SDK 客户端会缓存密钥,但 Secrets Manager 的密钥可能被轮换。你如果不用 TTL 刷新,可能读到旧值。建议设置合理的缓存时长,比如 5 分钟。
  • 日志泄露:打印 console.log(secret) 或者将密钥写进日志文件,这是大忌。我见过线上排查问题时,运维直接把密钥输出到日志里,结果日志平台所有人都能看到。
一个小技巧:调试时可以临时开启 SDK 日志(设置 logLevel: 'debug'),但务必在发布前关掉。我通常会在配置中心加一个开关,只有开发环境才开,生产环境强制静默。

推荐的生产配置组合

如果你现在要搭建一套生产环境,我建议直接用这个模板:

环境密钥获取方式配置方式
本地开发长期密钥(只限你自己的机器)环境变量 + .env 文件(不提交 Git)
测试环境长期密钥(每个项目独立子账号)配置文件 + AWS_PROFILE 切换
预发布/生产临时密钥(STS 或 IAM 角色)自动注入(ECS / EC2 元数据 / Lambda 执行角色)

这套方案我用了好几年,既灵活又安全。说白了,密钥管理没那么多花活——源头做对,过程加密,运行时自动,基本就不会出大问题。