今天週末來聊個輕鬆的小技巧,也是我之前犯過的錯 XD
前一天我們有聊到要改政策的權限,假設我們在前面有加了一條「拒絕列出使用者」。但之後進來的新人不想動別人寫的東西,就在最後面又加一條「允許列出使用者」:
先複習一下 Day 06 教的政策長相,一份權限政策裡面是一條一條的規則,每條規則主要就三個欄位:
| 欄位 | 意思 | 這篇會看到的值 |
|---|---|---|
Effect |
這條規則的效果:是放行還是擋下 | Allow(允許)或 Deny(拒絕) |
Action |
管哪一個動作,寫法是「服務:動作」 | iam:ListUsers,IAM 這個服務的「列出使用者」 |
Resource |
對哪些東西 | *,就是全部 |
JSON 裡還會看到三個包裝用的欄位:Version 是語法版本、Statement 是裝規則的清單、Sid 是這條規則的名字(選填,給自己看的,改了不影響效果)
念出來就像是:「允許或拒絕(Effect)做某個動作(Action)對某些東西(Resource)」
像 Allow + iam:ListUsers + *,就是「允許列出所有使用者」;把 Allow 換成 Deny,就變成「拒絕列出所有使用者」
回到那份政策。裡面同一個動作 iam:ListUsers 同時有一條 Allow(允許)、一條 Deny(拒絕)
這裡舉出兩個版本,唯一的差別是這兩條規則誰在前、誰在後:
| 順序 | 版本甲 | 版本乙 |
|---|---|---|
| 規則 1 | 允許 iam:ListUsers |
拒絕 iam:ListUsers |
| 規則 2 | 拒絕 iam:ListUsers |
允許 iam:ListUsers |
版本甲:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowList",
"Effect": "Allow",
"Action": "iam:ListUsers",
"Resource": "*"
},
{
"Sid": "DenyList",
"Effect": "Deny",
"Action": "iam:ListUsers",
"Resource": "*"
}
]
}
版本乙就是把兩條規則上下對調:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyList",
"Effect": "Deny",
"Action": "iam:ListUsers",
"Resource": "*"
},
{
"Sid": "AllowList",
"Effect": "Allow",
"Action": "iam:ListUsers",
"Resource": "*"
}
]
}
寫過前端可能就會直接心裡 OS:後面的蓋掉前面的啊,CSS 是這樣、變數重新賦值也是這樣
但 AWS 不是這樣 XD
AWS 官方文件講得很清楚:
所以每次你點一個東西,AWS 判斷的順序是這樣:

回到那兩個版本:甲和乙都有一條拒絕 iam:ListUsers,第一步就被抓到,兩個版本都拒絕。允許放前面放後面完全沒差
為什麼順序不重要?畢竟 AWS 不是從上往下讀到第一條就停
它是把這個人拿得到的每一份政策全部翻過一遍,先找有沒有拒絕;一條都沒有,才回頭找允許
兩個常見的錯誤名詞會是:
兩種都是被擋,但修法不一樣:前者要去找那條拒絕是誰寫的、為什麼寫;後者補一條允許就好
預設拒絕最常見的樣子是,一個人的政策只允許 iam:ListUsers,如果他好奇點進 EC2(AWS 租主機的服務)的頁面,就會被擋。沒有人擋他,是沒有人放行他。這時候去找「誰加了拒絕」是白找的,該確認的是「誰該幫他加允許,還是他本來就不該進去」
所以該做的不是在最後面加允許,而是回頭問那條拒絕是誰加的,以及為什麼加。要嘛拿掉它,要嘛這個人本來就不該列出使用者
剛剛說 AWS 判斷時會翻「這個人拿得到的每一份政策」,那一個人到底會從哪裡拿到政策?
我們來看一個人員調動的例子。小芸目前有兩份政策,名字分別叫 Lookup 和 Edit:
| 權限來源 | 掛在哪 | 允許什麼 |
|---|---|---|
| Lookup | 直接掛在小芸身上 | iam:ListUsers 列出使用者 |
| Edit | 掛在 Editors 群組,小芸是成員 | iam:UpdateUser 修改使用者 |
兩份政策都很短。Lookup 直接掛在小芸身上:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:ListUsers",
"Resource": "*"
}
]
}
Edit 掛在 Editors 群組上:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:UpdateUser",
"Resource": "*"
}
]
}
這次調動只做一件事:就是 把小芸移出 Editors 群組。兩份政策都沒有 Deny

所以移出群組之後:
iam:UpdateUser 會被拒絕,這拒絕是政策「沒寫到」那種拒絕iam:ListUsers 就照常運作~這邊有幾個很常見的誤會,順手清一下:
這就是實務上最容易出包的地方:要拔一個人的權限,得把每個來源都拔掉。這也是為什麼 Day 06 建議政策盡量掛群組、不要直接掛人:來源比較,查得也清楚些~
最後小結一下~
| 重點 | 記住這句 |
|---|---|
| 怎麼判斷政策權限 | 先找明確拒絕,有就擋;再找允許,有就過;都沒有也是擋 |
| 順序 | 政策裡允許、拒絕寫前寫後都一樣,拒絕永遠蓋過允許 |
| 兩種被擋 | 明確拒絕是有人寫了 Deny;預設拒絕是根本沒寫到 |
| 權限來源 | 直接掛在身上的+所在群組掛的,判斷時全部一起翻 |
| 拔權限 | 移出群組只斷那一個來源,身上直接掛的還在;要拔乾淨得每個來源都得拔 |
下次如果你聽到同事說「我加了一條允許在最後」、「他已經移出群組了」
你可以先問,這個人拿得到的政策,除了群組就沒其他來源哩?
希望這篇讓你看懂權限是怎麼算出來的,我們下篇見 :D