访问密钥会泄漏,是因为它存在
一句话总结
长期访问密钥的最佳策略是**根本不要创建。**通过扮演角色取得的临时凭据会在数小时后自动过期, 因此即使发生泄露,损失也会受到时间限制。
为什么需要它
AWS 密钥被提交到 GitHub 公共仓库的事故至今每天都在发生。 机器人会在几分钟内发现密钥,并启动加密货币挖矿实例,最终账单可能高达数千万韩元。
这里真正的问题不是误提交,而是那把密钥原本就存在。 长期密钥具有以下特征。
- 不会自行过期——在人工撤销前永远有效
- 很难追踪在哪里使用——因此人们害怕将其废止
- 很容易复制——会扩散到文档、聊天、环境变量和 CI 配置中
它如何运作
扮演角色的含义
角色是一组权限,**信任策略(trust policy)**决定“谁可以扮演这个角色”。
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
EC2 实例可以扮演这个角色。把角色附加到实例后,实例内运行的程序无需密钥就能取得凭据。 程序会从元数据服务自动获取凭据,并在过期前自动刷新。
总结如下。
| 长期访问密钥 | 角色(临时凭据) | |
|---|---|---|
| 过期 | 无 | 通常为 1~12 小时 |
| 分发 | 复制到文件或环境变量 | 自动注入 |
| 撤销 | 人工查找并废止 | 等待过期即可 |
| 追踪 | 无法明确由谁使用 | 按角色记录审计日志 |
服务账号密钥也存在同样的问题
Kubernetes 中也是如此。把云密钥作为 Secret 放进 Pod 的方式,会完整保留同样的风险。 应改用 OIDC 联合——通过集群签发的服务账号令牌扮演云角色(AWS 的 IRSA、 GCP 的 Workload Identity、Azure 的 Workload Identity)。关键在于让密钥从根本上不存在。
CI 也一样。与其把长期密钥放进 GitHub Actions 或 Gitea Runner,不如让它们通过 OIDC 扮演角色,从仓库 Secret 中彻底移除云密钥。
仍然需要长期密钥时
某些场景无法完全消除长期密钥,例如与外部 SaaS 集成。此时至少应做到以下几点。
- 创建专用主体——不要共享个人账号的密钥。
- 把权限缩小到该用途所需范围——通过 Condition 进一步限制 IP 和时间。
- 把**定期轮换(rotation)**制定为正式流程,并加入日历。
- 检查使用痕迹——最后使用时间过于久远时就删除。
第四项成本最低,效果却最明显。仅仅删除无人使用的密钥,就能大幅缩小攻击面。
会话与过期时间
扮演角色时需要指定会话时长。越短越安全,但过短会导致凭据在长任务执行期间过期。 实际工作中可以采用以下标准。
- 人员的控制台操作:约 1 小时
- CI 任务:略长于任务的最大执行时间
- 长时间批处理:让代码负责刷新凭据(SDK 通常会自动完成)
生产现场中的表现
- 在仓库中发现密钥 → 应立即废止,但因不知道在哪里使用而推迟废止。
- 在实例中放置密钥文件 → 附加角色后,就不再需要该文件。
- 整个团队共享同一把密钥 → 审计日志无法判断由谁执行操作。
扮演角色时的注意事项
角色确实比长期密钥更安全,但**如果信任策略写得过于宽松,这种安全性会完全消失。**事故通常发生在几个固定位置。
**允许任何人扮演的角色。如果把信任策略中的主体写得过宽,其他账号中的人就可能扮演该角色。为外部合作方开放权限时尤其常见,而且只限制对方账号 ID 还不够。**因为该账号中的任何人都可能扮演角色。向外部开放时,还要增加一个只有双方知道的标识符作为条件,防止第三方通过该账号绕过限制。
**身份联合中遗漏条件。**CI 通过 OIDC 扮演角色时,如果没有用条件限制具体仓库和分支,**任何使用该 CI 服务的仓库都可能扮演我们的角色。**这是最常见的错误,只需增加一行条件即可阻止。
**传递角色的权限。**创建资源时为该资源附加角色,本质上等于拥有“让资源代替我完成自己无权执行的操作”的权限。授予这项操作时,还必须限制可以附加哪些角色;否则,低权限用户可以创建附带管理员角色的资源,从而提升自己的权限。
**追踪角色链的终点。**当一个角色扮演另一个角色,而后者又继续扮演其他角色时,人很难追踪最终能够执行哪些操作。前一模块介绍的评估工具在此尤其有价值,通过规则限制角色链深度也是一种有效方法。
最后,临时凭据在有效期内同样无法撤销。即使收窄角色权限,已经签发的会话仍会继续存活。因此,把会话时间设短并不只是良好的安全习惯,而是事故发生时响应速度本身。
下一步内容
接下来将学习逐步收窄权限的顺序。从一开始就准确实现最小权限是不可能的。