第3章:IAM策略编写实践——最小权限原则
好了,聊完了IAM的角色和信任策略,咱们该动手写策略了。这一章我重点说说最小权限原则——说白了就是:给每个角色、每个用户刚刚好的权限,多一点都不行。听起来简单?我见过太多团队一开始图省事,直接挂个 AdministratorAccess,后来出事了才追悔莫及。
3.1 为什么最小权限这么重要?
你想想看,AWS 安全模型的核心是「共享责任」。云基础设施的物理安全亚马逊管,但你的数据、你的策略、你的密钥,那都得自己负责。权限给大了,一个不小心,开发者可能在测试环境把生产库删了。我有个客户,就因为给了一个实习生 s3:* 权限,结果他写脚本时把整个桶递归清空了……还好有版本控制,不然损失惨重。
最小权限原则的好处很明显:
- 缩小攻击面——哪怕某个凭证泄露了,能做的操作也有限。
- 减少误操作——没权限就干不了坏事,不管是恶意的还是手滑的。
- 审计更清晰——每条策略都能说清楚“为什么需要这个权限”。
核心观点:权限应该是「按需最小」,而不是「先给够再说」。你给一个只看日志的脚本 logs:DescribeLogGroups 就够了,别顺手加上 logs:*。
3.2 编写策略的第一步:用托管策略还是自定义策略?
AWS 提供了很多托管策略,比如 AmazonS3ReadOnlyAccess。我个人建议:能用托管策略的优先用,省事。但是!托管策略往往偏宽泛,比如 ReadOnlyAccess 几乎能读所有服务。如果你的场景只需要读某个特定桶,千万别偷懒。
我的经验是:先查一下有没有合适的托管策略作为起点,然后基于它做裁剪,或者直接写自定义策略。举个例子:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-important-data",
"arn:aws:s3:::my-important-data/*"
]
}
]
}
你看,我只给了 GetObject 和 ListBucket,没给 PutObject,更没给 DeleteObject。这就是最小权限的体现。
小技巧:用 AWS 的 IAM 访问分析器来检查你的策略是不是过于宽松。它会提醒你哪些权限超出实际使用范围。
3.3 善用条件键,给权限加「围栏」
光控制 Action 和 Resource 还不够。你还可以用 Condition 来限制:比如只能从公司 VPN 访问,或者只能操作特定标签的资源。我曾经给一个开发团队配置过:只允许使用 t3.micro 实例类型,避免他们一时兴起开了个昂贵的 p3.16xlarge。
条件键用得好的话,能把权限控制得非常精细。下面是我常用的几个:
| 条件键 | 用途 | 示例 |
|---|---|---|
aws:SourceIp |
限制来源 IP | 只允许公司内网 |
aws:RequestedRegion |
限制可操作的区域 | 只允许 ap-northeast-1 |
aws:ResourceTag |
限制带特定标签的资源 | 只允许操作 env=production 的 EC2 |
s3:prefix |
限制 S3 前缀路径 | 只允许访问 /logs/ |
举个实际策略:只允许从公司 IP 段访问,并且在东京区域操作 S3。
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
},
"StringEquals": {
"aws:RequestedRegion": "ap-northeast-1"
}
}
}
注意:条件键不是万能的。有些服务不支持某些条件键,你得去查服务特定的授权参考。写完之后最好用 IAM 策略模拟器验证一下,别想当然。
3.4 拒绝优先于允许——显式 Deny 是你的保险
IAM 的策略评估逻辑里有一条铁律:显式 Deny 永远覆盖任何 Allow。所以当你需要确保某些操作一定不能做时,就用 "Effect": "Deny"。比如,你希望所有用户都不得删除 S3 存储桶,就可以全局加一条:
{
"Effect": "Deny",
"Action": "s3:DeleteBucket",
"Resource": "*"
}
我本人习惯在账户的权限边界策略里先设几条硬性 Deny,比如禁止修改 CloudTrail 配置、禁止关闭多因素认证等。这就像给房子装了防盗门——就算不小心把钥匙给了不该给的人,他也绕不过去。
3.5 从浮夸到精确:迭代式的权限最小化
别指望第一次写出去的策略就完美。现实是:你一开始可能低估了业务需求,给少了导致应用报错;或者给多了,又得回头收紧。我建议采用迭代式:
- 基于最小知识写出初始策略——只赋权和文档里明确需要的 Action。
- 放到预发布环境跑一遍——看 CloudTrail 日志里有没有 AccessDenied 错误。
- 根据日志加回确实需要的权限——注意,每次只加一个 Action,不要一次加一堆。
- 定期用 IAM 访问分析器复查——把未使用的权限去掉。
你可能会问:这样是不是太繁琐?嗯,一开始确实有点麻烦。但一旦形成习惯,你的策略会越来越干净。我经历过一个项目,一开始给了一个 Lambda 执行角色 s3:*,后来发现它只读几个配置文件。优化后,策略从 20 行缩到 4 行,心里踏实多了。
3.6 一张图看懂最小权限策略设计流程
下面这张图总结了从我拿到一个需求,到最终落地最小权限策略的思考路径。嗯,画得比较糙,但逻辑是清晰的:
3.7 避坑指南:我踩过的几个雷
写策略的时候,有几个坑特别容易掉进去。我用自己的血泪史给你提个醒:
- 滥用通配符 *——我曾经给一个 DevOps 角色写了
"Action": "ec2:*",结果他顺手终止了一个正在跑批处理的实例。后来我全都改成精确 Action 列表,宁可多写几行。 - 忽略 Resource 的层级——S3 的桶和对象资源是分开的。比如
ListBucket针对桶 ARN,GetObject针对对象 ARN。少写一个/*就会报错。 - 条件键拼写错误——我有一次把
aws:SourceIp写成了aws:sourceIp(大小写不对),结果条件永远不生效,策略等于白写了。教训:多看官方文档的精确拼写。
建议:写完策略一定要用 aws iam simulate-custom-policy 或 IAM 策略模拟器跑一遍,用真实的请求参数验证。省钱省心。
3.8 小结:最小权限是习惯,不是一次性的工作
说了这么多,其实就一句话:权限越小,睡得越安稳。别管项目多赶,都要留出时间做权限评审。把最小权限原则嵌入到你的 CI/CD 流水线里,比如通过自动化工具扫描策略的宽松度。我自己现在每个新策略都必须经过两个步骤:同事 Code Review 加策略模拟器通过,才能合并到主分支。