人人都能学编程
English 开始学习
专项 · 云与 SRE第 3 课 / 共 5 课免费阅读

IAM 与最小权限 · 云与可靠性

云账号里,谁可以做什么?

课程目录

为什么需要它

云账号由权限策略来控制。策略太宽,一把泄露的密钥或一个 bug 就能变成对一切的访问:每个存储桶、每个数据库、每张账单。最小权限——只给每个应用它确实需要的权限,一点不多——是最有效的安全习惯之一,而它从正确读懂策略开始。

直觉理解

策略是一串语句。每条语句说:对这些资源上的这些操作,允许(Allow)或拒绝(Deny)。通配符很常见:s3:Get*、photos/*。

policy = [
    {"effect": "Allow", "actions": ["s3:GetObject", "s3:PutObject"], "resources": ["shop-photos/*"]},
    {"effect": "Deny",  "actions": ["s3:*"],                         "resources": ["shop-photos/private/*"]},
]

判断方法和 AWS IAM 一样(简化版):

  1. 找出操作和资源都匹配的语句。
  2. 只要有一条匹配的语句是 Deny → 拒绝。显式拒绝永远优先。
  3. 否则,只要有一条是 Allow → 允许。
  4. 否则 → 拒绝。没有任何语句允许的事情,一律不允许(隐式拒绝)。

最小权限的做法:列出应用真正要做的事(读照片、上传照片),只对这些资源允许这些操作。"actions": ["*"], "resources": ["*"] 正好相反。

定义

策略

A list of statements that allow or deny actions on resources.
允许或拒绝对资源执行某些操作的一组语句。

显式拒绝

A matching Deny statement. It overrides every Allow.
一条匹配的 Deny 语句。它压过所有 Allow。

最小权限

Granting only the actions and resources a job needs, nothing more.
只授予完成工作所需的操作和资源,一点也不多。

示例

通配符

动手试试

fnmatch 匹配 * 和 ? 的方式与 IAM 的模式相同。

import fnmatch

print(fnmatch.fnmatchcase("s3:GetObject", "s3:Get*"))
print(fnmatch.fnmatchcase("s3:PutObject", "s3:Get*"))
print(fnmatch.fnmatchcase("shop-photos/cats/1.jpg", "shop-photos/*"))
print(fnmatch.fnmatchcase("shop-photos", "shop-photos/*"))
输出
True
False
True
False
逐步执行
  1. L3
    • 匹配任意字符:Object。
    True
  2. L5这里的 * 也能跨过 /,所以文件夹下的一切都匹配。True
  3. L6模式要求名字后面有个 /,所以存储桶本身不匹配。False

允许、拒绝、和什么都没有

动手试试

显式拒绝压过允许;没有匹配就是不允许。

import fnmatch

def matches(patterns, value):
    return any(fnmatch.fnmatchcase(value, p) for p in patterns)

def allowed(policy, action, resource):
    hits = [s for s in policy if matches(s["actions"], action) and matches(s["resources"], resource)]
    if any(s["effect"] == "Deny" for s in hits):
        return False
    return any(s["effect"] == "Allow" for s in hits)

policy = [
    {"effect": "Allow", "actions": ["s3:GetObject", "s3:PutObject"], "resources": ["shop-photos/*"]},
    {"effect": "Deny", "actions": ["s3:*"], "resources": ["shop-photos/private/*"]},
]

print(allowed(policy, "s3:GetObject", "shop-photos/cat.jpg"))
print(allowed(policy, "s3:GetObject", "shop-photos/private/id.png"))
print(allowed(policy, "s3:DeleteObject", "shop-photos/cat.jpg"))
输出
True
False
False
逐步执行
  1. L7操作和资源都匹配的语句。
  2. L8只要有匹配的拒绝,就拒绝。
  3. L18两条语句都匹配;Deny 胜出。False
  4. L19没有任何语句允许删除:隐式拒绝。False

常见错误

对 "*" 允许 "*"

拥有全部权限的应用,任何 bug 或泄露的密钥都会变成整个账号被接管。列出它真正用到的操作。

以为 Allow 能压过 Deny

显式的 Deny 永远胜出,不管它来自哪里。「永远不许删除备份」这类护栏就是这么实现的。

长期有效的密钥

永不过期的访问密钥迟早会泄露。优先使用带短期凭证的角色,必须存在的密钥要定期轮换。

小测验

1. 一条语句允许对 `logs/*` 执行 `s3:*`;另一条拒绝对 `logs/*` 执行 `s3:DeleteObject`。应用能删除 `logs/a.txt` 吗?

  1. A不能:显式拒绝优先
  2. B能:s3:* 允许了
  3. C取决于语句的顺序
查看答案

答案:A

顺序无关。任何匹配的 Deny 都压过所有 Allow。

2. 一个策略只允许 `s3:GetObject`。执行 `s3:PutObject` 会怎样?

  1. A拒绝:没有任何语句允许它
  2. B允许:没有任何语句拒绝它
  3. C策略出错
查看答案

答案:A

隐式拒绝:没被允许的一律拒绝。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出判断每个请求

    准确写出它打印的内容。

  2. 改需求最小权限

    照片应用只需要读取和上传 shop-photos/uploads/ 下面的文件。它的策略却允许一切。把 POLICY 换成只对 shop-photos/uploads/* 允许 s3:GetObject 和 s3:PutObject 的策略。

  3. 从零写判断一个策略

    自己写一个 allowed(policy, action, resource)。每条语句有 "effect"("Allow" 或 "Deny")、"actions" 和 "resources"(带 * 和 ? 的模式列表)。规则:

    1. 只要有一个操作模式匹配 action,并且有一个资源模式匹配 resource,这条语句就适用
    2. 有适用的 Deny → False
    3. 否则有适用的 Allow → True
    4. 否则 False

    用 fnmatch.fnmatchcase(值, 模式) 来匹配。

在互动课里练这一课

打开互动课,这些例子都能直接改、直接运行,练习题提交马上判题。免费开始,不用注册。

互动课按顺序解锁:前面的课还没学,会先带你到课程地图。

本课术语

术语中文英文定义
IAM身份与访问管理Identity and access management: who may do what in a cloud account.
Least privilege最小权限Only the permissions a job needs.
Implicit deny隐式拒绝Anything not explicitly allowed is refused.