先放宽再收窄 vs 先收紧再放开
一句话总结
最小权限不是一次性设计完成的结果,而是通过测量不断收窄的过程。 没有人能预先知道程序会调用所有哪些 API。
为什么需要它
现在要部署一项新服务。即使查看文档,也无法准确知道它需要哪些权限。 因此,通常会在以下两种方式中选择一种。
A. 先宽后窄——从 s3:* 开始,让服务先运行起来,之后再缩小范围。
B. 先窄后宽——只添加明确需要的权限,每次遇到阻塞再增加一项。
现实中,采用 A 后,**负责收窄权限的提交永远不会到来。**服务一旦开始正常运行, 就没有人会再次修改权限。因此原则上应选择 B,但 B 会拖慢开发过程。
它如何运作
实务中采用的折中方案
1. 개발 환경에서만 넓게 연다 (운영 계정에는 절대 넣지 않는다)
2. 실제로 호출된 API 를 기록한다 (감사 로그·액세스 어드바이저)
3. 그 목록으로 정책을 생성한다
4. 스테이징에서 좁힌 정책으로 검증한다
5. 운영에는 좁힌 정책만 배포한다
关键在于第 1 步的环境隔离。只要明确规定哪些环境可以存在宽泛权限, “先开放,以后再收紧”就不会直接演变成生产事故。
第 2 步所需的数据由云平台提供——它能够显示某个主体最后一次在何时调用了哪个服务。 连续 90 天从未使用的权限,就是可以移除的候选项。
权限边界(permission boundary)
如果允许开发者创建角色,该开发者就可能创建一个权限比自己更高的角色。 权限边界正是用于阻止这种情况的机制。
실효 권한 = (붙은 정책) ∩ (권한 경계)
由于结果取交集,即使策略中写入边界之外的权限,该权限也不会生效。 它用于表达“可以自由创建角色,但绝不能超出这个范围”。
在组织层面,更上方还存在**服务控制策略(SCP)**之类的护栏。 它是作用于整个账号的 Deny,因此即使管理员也无法绕过。
几种常用护栏
| 护栏 | 阻止的行为 |
|---|---|
| 禁止使用未经批准的区域 | 在错误区域创建资源 |
| 禁止使用根账号 | 日常使用最高权限账号 |
| 禁止关闭审计日志 | 清除活动痕迹 |
| 禁止创建未加密的存储 | 默认设置错误 |
| 禁止配置公开访问 | 存储桶公开事故 |
仅仅设置这五项护栏,就能消除大多数常见事故。而且这些规则由系统强制执行, 不依赖人的注意力,因此能够长期保持有效。
收窄权限时经常遗漏的事项
- 看起来像读取的写入操作——
s3:GetObject是读取,但s3:PutObjectAcl会修改权限。 只根据名称分类会得出错误结论。 - 权限提升路径——
iam:PassRole、iam:CreatePolicyVersion等操作, 可能被用于给自己授予更大权限。 - 删除权限——很容易从清单中遗漏,造成的损失却最大。
生产现场中的表现
- 开发时用
*全部开放,并原样部署到生产 → 最常见的事故路径。 - 一半权限连续 90 天没有使用 → 从未查看过 Access Advisor。
- 开发者创建的角色达到管理员级别 → 没有设置权限边界。
人与机器的权限必须区别对待
逐步收窄最小权限时,人所用的权限与程序所用的权限性质不同。如果用同一种方式管理,两边都会出现偏差。
机器权限更容易收窄。程序执行的工作固定,行为变化时也会经过部署,因此记录实际调用并只授予相应权限的方法很有效。机器还应遵守不授予长期凭据的原则。把角色附加到实例或工作负载,使其自动获取短期凭据,就能从根本上消除密钥被提交到仓库或写入日志的事故。对于外部 CI 这类运行在云外的系统,如今也可以通过身份联合实现相同结构。
人的权限更难收窄。人员每次执行的工作不同,发生故障时还会突然需要平时不用的权限。因此,人的常驻权限应保持较低,同时建立一条在需要时临时提升权限的路径。通过审批取得数小时有效的权限,并把过程完整记录下来。如果缺少这种机制,最终所有人都会以“故障时不方便”为理由,长期持有高权限。
两种情况下,**凭据寿命越短,泄露后的价值就越低。**因此,缩短寿命与收窄权限同样重要,而且前者通常更容易完成。逐行调整策略可能需要数周,但把长期密钥替换为角色只需完成一次,效果也会立即显现。
最后,还要建立清理离职人员和已下线服务的流程。任何组织都有授予权限的流程,却经常没有撤销权限的流程。无人使用的账号和角色不断累积,本身就会扩大攻击面;时间久了,人们甚至无法判断哪些对象仍在使用,也就不敢清理。定期列出连续 90 天未使用的主体,是阻止这一问题成本最低的方法。
下一步内容
接下来通过真实案例了解,当这些机制全部失效时会发生什么事故。