第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 本章知识体系

下面这张图帮你理清资源定义的核心脉络:

资源(Resource)定义知识体系 ARN 资源定义 ARN 格式解析 通配符(* 和 ?) 多资源匹配规则 资源层级关系 6字段结构 服务差异 * 多字符 ? 单字符 数组形式 通配合并 单星号 /*** 双星号 /** 💡 核心要点 • ARN 是资源的唯一标识,6段结构缺一不可 • 通配符 * 匹配多字符,? 匹配单字符,层级用 / 分隔 • 单星号只匹配当前层级,双星号递归匹配所有层级

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 里的文件就读不到了。

我的建议:写资源策略时,先画一个资源树,标清楚层级关系。然后问自己三个问题:

  1. 要匹配哪些层级?
  2. 用单星号还是双星号?
  3. 有没有需要排除的资源?

想清楚再动笔,能省下大量排错时间。