第2章 策略语言基础:JSON结构解析
权限策略这东西,说白了就是一堆JSON。你想想看,云厂商那么多,为什么策略语言长得都差不多?因为它们都借鉴了AWS IAM的那套设计。我最早接触策略配置时,第一反应是「这不就是个JSON嘛,有什么好学的」——结果第一次上线就把存储桶权限配成了公开读写,差点被运维同事请喝茶。
嗯,咱们今天就把这个JSON结构拆开揉碎了讲。你掌握了这章,后面所有策略配置都会变得很自然。
2.1 策略的骨架:Version + Statement
一个完整的权限策略,其实就两个顶层字段:Version 和 Statement。我习惯把Version想象成「协议版本号」,Statement就是「具体的规则列表」。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:GetObject",
"Resource": "acs:oss:*:*:my-bucket/*"
}
]
}
你看,结构非常清晰。Version固定写死,Statement是一个数组——这意味着你可以放多条规则。我在项目中见过有人把几十条Statement塞到一个策略里,说实话,可读性很差。我建议每条策略控制在5条Statement以内,超过就拆成多个策略。
核心要点:Version目前主流是 2012-10-17,部分老系统还在用 2008-10-17。新写策略一律用新的,别问为什么,问就是兼容性。
2.2 Statement结构拆解
Statement里的每个对象,都有几个固定字段。我列个表,你一眼就能看明白:
| 字段 | 是否必填 | 说明 |
|---|---|---|
| Effect | 必填 | Allow 或 Deny,决定是允许还是拒绝 |
| Action | 必填 | 操作列表,比如 oss:GetObject、ecs:DescribeInstances |
| Resource | 必填 | 资源ARN,指定这条规则作用在哪些资源上 |
| Condition | 选填 | 条件约束,比如IP限制、时间限制 |
| Principal | 选填 | 主体,通常用在资源策略里,身份策略不需要 |
这里有个坑——Principal字段。我刚开始做跨账号授权时,死活想不通为什么策略不生效。后来发现,身份策略(挂在用户/角色上的)不需要写Principal,只有资源策略(挂在存储桶/队列上的)才需要。这个区别,你记一下,后面章节会反复用到。
2.3 Effect字段:Allow vs Deny
Effect只有两个值:Allow 和 Deny。看起来简单,但它们的优先级关系,很多人搞混。
我直接说结论:Deny优先于Allow。哪怕你写了100条Allow,只要有一条Deny命中,结果就是拒绝。为什么会这样?因为安全设计上,拒绝必须比允许更「强硬」,否则你没法做例外控制。
我曾经踩过的坑:给一个运维账号配了全读写权限(Allow *),但忘了某个API默认有Deny策略。结果那个账号所有操作都正常,唯独不能调用某个关键接口。排查了整整一下午,最后发现是系统内置的一条Deny策略在作祟。所以,遇到权限异常,先查Deny。
Effect的评估逻辑,我画了张图,你一看就懂:
这个流程你记住三个字:显式Deny > 显式Allow > 隐式Deny。隐式Deny就是「你没写Allow,那就默认拒绝」。很多新手以为没写Deny就是允许,其实恰恰相反——没写Allow就是拒绝。
2.4 实战:写一个最小策略
光说不练假把式。咱们写一个真实场景的策略:允许某个用户读取指定存储桶中的文件。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:GetObject",
"oss:ListObjects"
],
"Resource": [
"acs:oss:*:*:my-bucket",
"acs:oss:*:*:my-bucket/*"
]
}
]
}
注意两个细节:
- Action用了数组——虽然只有两个操作,但用数组写更规范,方便以后扩展
- Resource写了两条——一条给存储桶本身(用于ListObjects),一条给桶内文件(用于GetObject)。我见过有人只写了桶的ARN,结果GetObject一直403
我的小技巧:写Resource时,如果拿不准ARN格式,先去云厂商的控制台复制。每个资源都有对应的ARN模板,手写容易漏掉分区或账号ID。我早期手写过一次,把 oss:* 写成了 oss:*:,多了一个冒号,策略直接解析失败。
2.5 常见错误与排查思路
策略配置出错,通常就这几种情况:
- JSON格式错误——多了一个逗号,少了一个引号。我建议用在线JSON校验工具先过一遍
- Version写错——用了旧版本,新功能不识别
- Resource遗漏——只写了父资源,没写子资源(比如只写了存储桶,没写桶内对象)
- Action名称拼错——大小写敏感,
GetObject写成getobject就不认
排查时,我习惯先看「模拟验证」工具。大部分云平台都提供策略模拟器,你把策略贴进去,选一个操作,它会告诉你「Allow还是Deny,以及为什么」。这个工具救过我很多次。
嗯,JSON结构这部分就这些。你只要记住Version固定、Statement是数组、Effect只有Allow和Deny、Deny优先,后面学Condition和Principal就会轻松很多。