第4章 资源(Resource)定义:从ARN格式到层级匹配
资源定义这块,说白了就是告诉系统「你到底要管什么东西」。我见过不少新手,策略写了一大堆,结果权限死活不对——十有八九是资源ARN写错了。今天咱们就把这个坑填平。
4.1 ARN格式解析:资源的身份证
ARN的全称是Amazon Resource Name。你可以把它理解成云上每个资源的「身份证号」。没有这个,策略就找不到目标。
标准ARN长这样:
arn:partition:service:region:account-id:resource-type/resource-id
拆开来看,一共6个字段:
| 字段 | 含义 | 示例值 |
|---|---|---|
| partition | 分区,区分公有云/中国区/政府云 | aws、aws-cn、aws-us-gov |
| service | 服务名,比如S3、EC2、IAM | s3、ec2、iam |
| region | 区域,全局服务用空字符串 | us-east-1、cn-north-1 |
| account-id | 12位AWS账号ID | 123456789012 |
| resource-type | 资源类型,部分服务需要 | bucket、instance、user |
| resource-id | 具体资源标识 | my-bucket、i-0abcd1234 |
重点记住:IAM策略里的资源字段,必须写完整的ARN。少一个冒号,策略就失效。
举个实际例子。我想引用一个S3存储桶:
arn:aws:s3:::my-data-bucket
注意这里region和account-id都是空的,但冒号不能少。S3的ARN格式比较特殊,我刚开始写的时候经常漏冒号,后来养成了习惯——写完数一遍冒号,一共6段。
4.2 资源通配符:* 和 ? 的用法
实际工作中,你不可能给每个资源单独写一条策略。通配符就是用来解决这个问题的。
4.2.1 星号(*):匹配任意多个字符
* 是最常用的通配符。它匹配0个或多个字符。
# 匹配所有S3存储桶
arn:aws:s3:::*
# 匹配以"prod-"开头的存储桶
arn:aws:s3:::prod-*
# 匹配所有EC2实例
arn:aws:ec2:us-east-1:123456789012:instance/*
我的习惯:写策略时先用最宽的通配符测试,确认能跑通,再逐步收紧。这样排查问题快很多。
4.2.2 问号(?):匹配单个字符
? 用得少,但特定场景很管用。它只匹配一个字符。
# 匹配 bucket-a, bucket-b, bucket-c ... 但不匹配 bucket-ab
arn:aws:s3:::bucket-?
我曾经遇到一个场景:客户有10台开发服务器,命名是 dev-01 到 dev-10。用 dev-?? 刚好匹配全部,又不会误伤 dev-1 这种旧命名。
4.3 多资源匹配规则
一个策略里可以写多个资源ARN。有两种写法:
4.3.1 数组形式
"Resource": [
"arn:aws:s3:::bucket-a",
"arn:aws:s3:::bucket-b",
"arn:aws:s3:::bucket-c"
]
4.3.2 通配符合并
"Resource": "arn:aws:s3:::bucket-*"
这里有个关键点:数组里的每个ARN是「或」的关系。只要匹配其中任意一个,就算匹配成功。
我曾经踩过的坑:在数组里混用了不同服务类型的ARN。比如S3的ARN和EC2的ARN写在一起,结果S3操作时报错说资源不存在。后来我才意识到——不同服务的ARN格式不一样,不能混在一个数组里用。
4.4 资源层级关系
云资源是有父子关系的。比如S3存储桶下面有对象,IAM用户组下面有用户。理解层级关系,才能写出精确的策略。
4.4.1 层级表示法
用斜杠 / 表示层级:
# S3对象层级
arn:aws:s3:::my-bucket/path/to/object.txt
# IAM用户层级
arn:aws:iam::123456789012:user/developers/alice
4.4.2 通配符与层级
通配符在层级中的行为需要特别注意:
# 只匹配 my-bucket 下的直接子对象
arn:aws:s3:::my-bucket/*
# 匹配 my-bucket 下所有层级的对象
arn:aws:s3:::my-bucket/**
这个区别很微妙。单星号只匹配一层,双星号匹配所有层级。我见过有人用单星号想匹配所有子目录,结果漏掉了深层文件。
4.4.3 层级匹配的常见误区
| 写法 | 匹配范围 | 常见误解 |
|---|---|---|
arn:aws:s3:::bucket/* |
bucket下的直接子对象 | 以为能匹配子目录中的文件 |
arn:aws:s3:::bucket/** |
bucket下所有层级对象 | 以为只匹配文件,不匹配目录 |
arn:aws:s3:::bucket |
仅存储桶本身 | 以为包含桶内对象 |
arn:aws:s3:::bucket/*.jpg |
bucket下所有.jpg文件 | 以为能匹配子目录中的.jpg |
记住这个原则:资源ARN匹配是精确匹配 + 通配符展开。不会自动递归到子层级。需要递归就显式写 **。
4.5 本章知识体系
下面这张图帮你理清资源定义的核心脉络:
4.6 实战:写一个完整的资源策略
咱们来写一个真实场景。假设你有一个S3存储桶 company-data,里面按部门分目录:
company-data/
├── engineering/
│ ├── code-reviews/
│ └── builds/
├── marketing/
│ ├── campaigns/
│ └── analytics/
└── shared/
└── templates/
需求是:工程团队只能访问 engineering 目录下的所有内容。策略这样写:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::company-data/engineering/**"
}
]
}
注意这里用了 **,因为 engineering 下面还有两层子目录。如果用 *,就只能访问 engineering 下的直接子对象,code-reviews 里的文件就读不到了。
我的建议:写资源策略时,先画一个资源树,标清楚层级关系。然后问自己三个问题:
- 要匹配哪些层级?
- 用单星号还是双星号?
- 有没有需要排除的资源?
想清楚再动笔,能省下大量排错时间。