桶策略入门:概念、区别与为什么需要细粒度控制

做云存储的,尤其是跟对象存储打交道的同行,一定绕不开「桶策略」这个东西。我最早接触它的时候,脑子里全是问号——这玩意儿跟 IAM 策略到底什么关系? 后来踩了几个坑才彻底搞明白。

说白了,桶策略是直接挂载在存储桶(Bucket)上的一份 JSON 权限声明。它告诉 AWS(或者阿里云、腾讯云):谁,在什么条件下,能对桶里的对象做什么操作。

一句话总结:桶策略是桶的“门卫”,IAM 策略是账号的“身份证”。两者配合使用,但分工完全不同。

桶策略 vs IAM 策略:一张表说清楚

对比维度 桶策略 IAM 策略
挂载位置 直接绑定到特定存储桶 绑定到用户、用户组或角色
作用范围 仅影响该桶及桶内对象 影响账号下所有授权资源
授权对象 可以授权给匿名用户、其他 AWS 账号 只能授权给本账号内的身份
控制粒度 支持路径级前缀、IP 条件、VPC 端点 支持更复杂的条件键和资源级控制
常见用途 公开读取、跨账号共享、访问日志写入 用户权限分工、角色临时权限
最大声明数 单个桶最多 20KB(JSON 文本) 每个策略最多 6 个声明,5120 字符

你看这个表格就清楚了。我当年刚开始做权限配置时,总喜欢把所有权限塞到 IAM 策略里,结果发现:跨账号授权根本没法用 IAM 策略做——因为 IAM 策略只能管自己账号的人。而桶策略可以直说「允许某个外部账号的某些用户读我这个桶」。这个差异很关键。

为什么需要细粒度控制?

举个实际场景。我们公司有个数据分析部门,需要读取生产环境某个日志桶里 /logs/2024/ 这个前缀下的所有文件。但他们不能碰 /logs/2023/ 之前的归档数据。

如果只用 IAM 策略给整个桶的 s3:GetObject 权限,那他们不小心就能访问到老归档。这谁受得了?

用桶策略加上 StringLike 条件限定前缀,就能精确到路径级别。我有个客户甚至要求「只允许在工作时间 09:00-18:00 通过办公网段 VPC 端点访问」,这些都能在桶策略的 Condition 里写死。

注意:细粒度不是越细越好。我曾经见过一个桶策略写了 30 多个声明,每个声明带 5 个条件,最后连团队内部都搞不清这个桶到底对谁开放了。推荐声明个数控制在 10 个以内,必要时配合 IAM 策略拆分。

桶策略的结构长什么样?

标准的桶策略 JSON 包含几大块:Version、Statement 数组,每个 Statement 里又有 Effect、Principal、Action、Resource、Condition。下面是一个最简单的公开读策略示例:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}

嗯,这里要注意:Principal: "*" 代表允许所有匿名用户。如果你只想让某个特定账号访问,就得写成 Principal: { "AWS": "arn:aws:iam::123456789012:root" }。我刚开始就把 "*" 当通配符随意用,结果桶变成公开读了……还好是测试环境。

你以为的「允许」和实际的「允许」

桶策略的生效逻辑是显式允许 > 显式拒绝 > 默认拒绝。但这里有个容易踩的坑:如果同时存在 IAM 策略允许和桶策略拒绝,那么最终结果是拒绝。因为拒绝优先级最高。

我曾经有个项目,运维组给一个桶写了桶策略拒绝来自非办公 IP 的访问,但数据分析组的 IAM 策略是允许所有 s3:GetObject 的。结果数据分析组在办公区外死活下载不了文件——桶策略的拒绝直接盖过了 IAM 策略的允许。

解决方案很简单:在桶策略里把需要的条件写清楚,或者干脆把拒绝逻辑放到 IAM 策略的 NotIpAddress 条件里。优先用 IAM 策略做身份级别的条件控制,用桶策略做资源级别的边界控制。

知识体系一张图

下面这张 SVG 图概括了桶策略在整个存储权限体系中的位置和核心要素:

桶策略知识体系 权限管理入口 IAM 策略(身份侧) 桶策略(资源侧) JSON 结构 Principal + Action + Resource Condition 细粒度条件 桶策略:挂桶、跨账号、匿名访问 IAM策略:挂身份、本账号、复杂条件 细粒度:路径/ IP/ 时间/ VPC端点 拒绝优先于允许,显式声明生效

什么时候必须用桶策略?

  • 公开访问:比如静态网站托管,桶策略要声明 Principal: "*" + s3:GetObject。
  • 跨账号共享:其他账号的 IAM 用户通过你桶策略的 Principal 授权后才能访问。
  • VPC 端点限制:只允许通过某个 VPC 端点访问桶,这是 IAM 策略不好直接做的。
  • 日志写入权限:比如启用 S3 访问日志时,目标桶需要桶策略允许源账号的 S3:PutObject。
  • 对象级条件控制:按前缀、标签、加密状态等条件限制操作。
核心结论:桶策略适合做资源边界控制,IAM 策略适合做身份边界控制。两者协同,才能做出安全又灵活的权限方案。别想着只用其中一个解决所有问题。

其实细粒度控制的好处远不止安全。我记得有一次,业务部门要求临时给某个第三方审计开放桶的只读权限。如果用 IAM 策略,我需要创建临时 IAM 用户、分配权限、再删除——耗时又容易遗留影子账号。而用桶策略,直接在桶上追加一条带 Principal 和 Condition(IpAddress) 的声明,审计结束后删除即可。前后 5 分钟搞定,不留残留。

嗯,这一块理解透了,后面的实操配置才能真正上手。你做权限配置时,脑子里要时刻想着:这个权限是该写在桶策略还是 IAM 策略里? 想清楚再动手,比写完了再改要快得多。