1. ARN 是什么
ARN 是 AWS 给每个资源起的完整名字。资源自己的名字可能和别人的重复,ARN 不会重复。原因是 ARN 除了资源名,还写明了这个资源属于哪个服务、哪个 Region、哪个账户。
2. ARN 由六段组成
各段之间用冒号隔开。例如:
arn:aws:lambda:ap-northeast-1:123456789012:function:order-api从左到右:
arn:开头固定写 arn。aws:分区。标准 AWS 写aws,中国区写aws-cn。不同分区完全分开,账户和权限都不互通。lambda:哪个服务。ap-northeast-1:哪个 Region,这里是东京。123456789012:哪个账户,固定 12 位数字。function:order-api:资源本身,这里是名叫 order-api 的函数。
3. 有些段是空的
不是每个 ARN 都六段写满。
IAM 角色不属于任何 Region,所以 Region 那一段空着:
arn:aws:iam::123456789012:role/app-roleS3 bucket 的名字在全 AWS 都不能重复,只靠名字就能确定是哪个 bucket,所以 Region 和账户两段都空着:
arn:aws:s3:::my-bucket段是空的,冒号也照样保留,所以会出现两个或三个冒号连在一起。
4. 最后一段,每个服务写法不同
AWS 没有统一规定最后一段怎么写:
- Lambda 用冒号:
function:order-api - EC2 用斜杠:
instance/i-0abc123 - SNS 只写名字,不写类型:
order-events
这会带来一个具体问题。最后一段里也可能出现冒号,比如带版本号的 Lambda:function:order-api:7。程序拆 ARN 时,只能按前五个冒号拆,剩下的部分整个算作最后一段。按所有冒号拆,最后一段就会被拆碎。
5. ARN 最常用在权限里
IAM 权限规则写的是:谁,可以对哪个资源,做什么操作。“哪个资源”就用 ARN 来写。
例如,“允许读取 my-bucket 里的所有文件”:
操作:s3:GetObject 资源:arn:aws:s3:::my-bucket/**表示任意内容,my-bucket/*就是 my-bucket 里的所有文件。
6. 容易出错的五个地方
第一,写死了aws。模板里直接写arn:aws:...,到中国区就不能用,因为中国区要求写arn:aws-cn:...。
第二,S3 的 bucket 和文件是两种 ARN。
- 列出 bucket 里有哪些文件,资源要写 bucket 本身:
arn:aws:s3:::my-bucket - 读写某个文件,资源要写到文件:
arn:aws:s3:::my-bucket/*
只写其中一种,另一类操作就会被拒绝。
第三,Lambda 带版本和不带版本是两个 ARN。function:order-api和function:order-api:prod在权限里是两个不同的字符串。只给了前一个的权限,用后一个调用会被拒绝,所以两个都要写。
第四,角色被使用时,显示的 ARN 会变。角色本身的 ARN 是:
arn:aws:iam::123456789012:role/service-role/app-role程序用这个角色干活时,日志里记录的身份是:
arn:aws:sts::123456789012:assumed-role/app-role/会话名服务从 iam 变成了 sts,中间的service-role/也没有了。拿这两个字符串直接比较,会判断成不相等。
第五,删掉再建同名资源,ARN 不变。大多数资源的 ARN 由名字组成,所以删掉后再用同名建一个,ARN 一模一样,原来写给旧资源的权限会自动用到新资源上。S3 风险最大,因为 bucket 的 ARN 里没有账户:你删掉一个 bucket 后,别的账户可以建同名 bucket,你的程序可能就把数据写进了别人的 bucket。
IAM 角色是例外。删掉再同名重建后,原来信任它的规则不会自动信任新角色,需要重新保存这些规则。
7. 实际该怎么做
- 不要在模板和代码里写死分区、Region 和账户,用工具提供的变量自动填入。
- 需要某个资源的 ARN 时,优先用 AWS 创建资源后返回的那个,不要自己拼。
- 程序里要拆 ARN,用 AWS SDK 自带的方法。
- 不确定某个服务的 ARN 怎么写,查 AWS 官方的 Service Authorization Reference,每个服务的格式都列在那里。