LabHub
学习 学习路径 课程

云权限设计

访问密钥会泄漏,是因为它存在

在 LabHub 中继续学习

一句话总结

长期访问密钥的最佳策略是**根本不要创建。**通过扮演角色取得的临时凭据会在数小时后自动过期, 因此即使发生泄露,损失也会受到时间限制。

概念图: 根本不要创建。 · 那把密钥原本就存在。 · 信任策略(trust policy) · OIDC 联合

为什么需要它

AWS 密钥被提交到 GitHub 公共仓库的事故至今每天都在发生。 机器人会在几分钟内发现密钥,并启动加密货币挖矿实例,最终账单可能高达数千万韩元。

这里真正的问题不是误提交,而是那把密钥原本就存在。 长期密钥具有以下特征。

它如何运作

扮演角色的含义

角色是一组权限,**信任策略(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 集成。此时至少应做到以下几点。

  1. 创建专用主体——不要共享个人账号的密钥。
  2. 权限缩小到该用途所需范围——通过 Condition 进一步限制 IP 和时间。
  3. 把**定期轮换(rotation)**制定为正式流程,并加入日历。
  4. 检查使用痕迹——最后使用时间过于久远时就删除。

第四项成本最低,效果却最明显。仅仅删除无人使用的密钥,就能大幅缩小攻击面。

会话与过期时间

扮演角色时需要指定会话时长。越短越安全,但过短会导致凭据在长任务执行期间过期。 实际工作中可以采用以下标准。

生产现场中的表现

扮演角色时的注意事项

角色确实比长期密钥更安全,但**如果信任策略写得过于宽松,这种安全性会完全消失。**事故通常发生在几个固定位置。

**允许任何人扮演的角色。如果把信任策略中的主体写得过宽,其他账号中的人就可能扮演该角色。为外部合作方开放权限时尤其常见,而且只限制对方账号 ID 还不够。**因为该账号中的任何人都可能扮演角色。向外部开放时,还要增加一个只有双方知道的标识符作为条件,防止第三方通过该账号绕过限制。

**身份联合中遗漏条件。**CI 通过 OIDC 扮演角色时,如果没有用条件限制具体仓库和分支,**任何使用该 CI 服务的仓库都可能扮演我们的角色。**这是最常见的错误,只需增加一行条件即可阻止。

**传递角色的权限。**创建资源时为该资源附加角色,本质上等于拥有“让资源代替我完成自己无权执行的操作”的权限。授予这项操作时,还必须限制可以附加哪些角色;否则,低权限用户可以创建附带管理员角色的资源,从而提升自己的权限。

**追踪角色链的终点。**当一个角色扮演另一个角色,而后者又继续扮演其他角色时,人很难追踪最终能够执行哪些操作。前一模块介绍的评估工具在此尤其有价值,通过规则限制角色链深度也是一种有效方法。

最后,临时凭据在有效期内同样无法撤销。即使收窄角色权限,已经签发的会话仍会继续存活。因此,把会话时间设短并不只是良好的安全习惯,而是事故发生时响应速度本身。

下一步内容

接下来将学习逐步收窄权限的顺序。从一开始就准确实现最小权限是不可能的。