使用资源策略保护存储桶

AWSBeginner
立即练习

介绍

存储桶所有者希望授予一个报表角色访问权限,并保护私有数据。你将附加存储桶策略,与角色自身的策略比较,并测试匹配的 Deny 如何影响访问。

请先完成 使用 IAM 角色的临时凭据 和 为报表读取者授予最小权限。这个全新 VM 提供 default、report-role 和 other-role;角色配置档已能获取临时会话。使用 /home/labex/project 和 AWS View。请保密凭据和缓存。

认证考点

认证 考点 本实验练习
Cloud Practitioner (CLF-C02) 任务 2.3 资源策略与显式拒绝的优先规则。
Solutions Architect – Associate (SAA-C03) 任务 1.1 资源策略与显式拒绝的优先规则。
Developer – Associate (DVA-C02) 任务 2.1 资源策略与显式拒绝的优先规则。
CloudOps Engineer – Associate (SOA-C03) 任务 4.1 资源策略与显式拒绝的优先规则。
Security – Specialty (SCS-C03) 任务 4.2 基础练习:资源策略与显式拒绝的优先规则。
Data Engineer – Associate (DEA-C01) 任务 4.2 基础练习:资源策略与显式拒绝的优先规则。
DevOps Engineer – Professional (DOP-C02) 任务 6.1 基础练习:资源策略与显式拒绝的优先规则。
Solutions Architect – Professional (SAP-C02) 任务 2.3 基础练习:资源策略与显式拒绝的优先规则。

实验概览

概念图:针对同账户的报表请求,比较角色身份策略与 S3 桶策略;匹配的显式 Deny 优先于 Allow。

从存储桶授予一个角色访问权限

在本步骤中,你将附加资源策略,授予 ReportReader 对 reports 前缀的访问权限。与身份策略不同,存储桶策略必须指定 Principal。使用标识角色的 IAM 角色 ARN;assumed-role 会话 ARN 则标识该角色的一次使用。

你已经从身份一侧授予访问权限;现在由桶所有者从资源一侧授权。两个角色配置已准备好,因此保持其信任不变,专注于桶策略和角色权限策略如何影响同一请求。

资源策略(resource policy)存储在资源上。S3 存储桶策略(bucket policy)就是一个例子:其中的 Principal 标识语句针对谁的请求。将它与存储在用户或角色上的身份策略比较。

确认两个活动会话身份,以及报表角色最初为空的权限策略列表。

cd /home/labex/project
aws sts get-caller-identity --profile report-role --query Arn --output text
aws sts get-caller-identity --profile other-role --query Arn --output text
aws iam list-role-policies --role-name ReportReader

预期为 assumed-role/ReportReader/report-run、assumed-role/OtherReader/other-run,以及空的 PolicyNames 列表。验证为角色身份本身不授权 S3 访问。测试当前读取:

aws s3api get-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt before.txt || true

预期为 AccessDenied。|| true 防止预期失败中断粘贴序列。连接失败不能证明拒绝。

编写存储桶策略。GetObject 授予对象读取,Resource 将范围限定为这一个桶的 reports/。角色 Principal 排除 OtherReader,不授予公开访问。

cat > bucket-policy.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-bucket-policy --bucket labex-iam04-reports --query Policy --output text

存储桶策略现在存储在桶上,而非附加到角色。在同账户内,只要没有相关 Deny 阻止,这个适用的资源 Allow 可以在没有独立角色身份 Allow 的情况下授予角色访问权限。

aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt
aws s3api get-object --profile other-role --bucket labex-iam04-reports --key reports/today.txt other-denied.txt || true
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key private/payroll.txt private-denied.txt || true
aws s3api get-object --profile report-role --bucket labex-iam04-reference --key reference.txt reference-denied.txt || true

ReportReader 获得 Daily orders: 145;另外三个请求均获得 AccessDenied。存储桶授权不覆盖其他角色、其他前缀或其他桶。AWS View 发起相同的实际角色读取。

在额外身份 Allow 下保护私有数据

在本步骤中,你将观察角色身份授权如何与存储桶授权组合,再使用桶 Deny 保护私有数据。对于这些同账户请求,适用的 Allow 合并生效;两种策略来源不会自动取交集。任一适用策略来源中的显式 Deny 都优先于 Allow。

本实验同账户请求使用的两种策略来源:匹配的显式 Deny 优先于 Allow。

临时扩大 ReportReader 的身份读取范围,允许读取这个练习桶中的对象。这个受控比较使用合成数据,不授予其他桶访问权限。

cat > role-read.json <<'JSON'
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/*"}]}
JSON
aws iam put-role-policy \
  --role-name ReportReader \
  --policy-name ReadAllOwned \
  --policy-document file://role-read.json
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key private/payroll.txt private-before-deny.txt
cat private-before-deny.txt

预期为 Synthetic payroll: restricted。即使桶 Allow 只覆盖 reports/,身份 Allow 仍适用。添加限定于该角色和 private 前缀的桶 Deny,同时保留报表 Allow。

cat > bucket-policy.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"},
    {"Effect":"Deny","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/private/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key private/payroll.txt private-denied.txt || true
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt

尽管有身份 Allow,私有对象现在仍返回 AccessDenied;报表仍返回 145。Deny 指定 ReportReader,因此操作员仍可以查看并保留素材。语句顺序不会使 Allow 覆盖匹配的 Deny。

确认身份 Deny 优先于存储桶 Allow

在本步骤中,你将测试相反方向:角色身份 Deny 优先于桶 Allow。保留当前读取授权,添加针对 reports 前缀写入的 Deny。

cat > role-read.json <<'JSON'
{"Version":"2012-10-17","Statement":[
  {"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/*"},
  {"Effect":"Deny","Action":"s3:PutObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
]}
JSON
aws iam put-role-policy \
  --role-name ReportReader \
  --policy-name ReadAllOwned \
  --policy-document file://role-read.json

为受控测试优先级,临时为相同角色和写入前缀添加桶 Allow。先应用身份 Deny,使报表始终受保护。

cat > bucket-write-test.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"},
    {"Effect":"Deny","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/private/*"},
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:PutObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-write-test.json
aws s3api put-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt --body upload.txt || true

即使桶允许,预期 PutObject 仍为 AccessDenied。身份 Deny 优先。立即恢复上一步保存的两语句策略,移除临时写入 Allow。

aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt
aws s3api get-object --profile other-role --bucket labex-iam04-reports --key reports/today.txt other-denied.txt || true

报表必须仍为 Daily orders: 145,OtherReader 仍被拒绝。临时写入授权已移除。AWS View 在实际读取结果旁显示桶策略和角色身份策略。

存储桶和身份策略保护报表. 示例:ReportReader 可以读取报表,而两个角色对私有及参考对象的读取都被拒绝。存储的策略显示独立授权来源和显式拒绝;展开的报表包含实际返回字节。

移除两种授权来源并清理

在本步骤中,你将在删除练习数据前撤回两种策略来源。如果另一个策略仍授予相同操作,只移除一个 Allow 并不足够。

删除桶策略,再重复报表读取。ReadAllOwned 仍通过角色身份策略授予读取。

aws s3api delete-bucket-policy --bucket labex-iam04-reports
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt remaining-grant.txt
cat remaining-grant.txt

预期为 Daily orders: 145。现在删除 ReadAllOwned,并在报表仍存在时再次测试。

aws iam delete-role-policy --role-name ReportReader --policy-name ReadAllOwned
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt revoked.txt || true
aws iam list-role-policies --role-name ReportReader

预期为 AccessDenied 和空策略列表。已准备好的角色及其调用者信任保持完整;你在移除本练习创建的 S3 授权。

aws s3api delete-object --bucket labex-iam04-reports --key reports/today.txt
aws s3api delete-object --bucket labex-iam04-reports --key private/payroll.txt
aws s3api list-objects-v2 --bucket labex-iam04-reports

在这个成功响应中检查 KeyCount: 0,再删除空报表桶并确认参考字节。

aws s3api delete-bucket --bucket labex-iam04-reports
aws s3api list-buckets --query 'Buckets[].Name'
aws s3api get-object --bucket labex-iam04-reference --key reference.txt reference.txt
cat reference.txt

只剩下参考桶,内容为 Platform reference: keep。网络错误不是删除证据。AWS View 现在显示没有桶策略或角色权限策略,以及 Reports bucket removed。一次性环境结束时,已准备好的身份、素材和本地临时缓存会被回收。

总结

你使用 Principal 通过桶策略授予一个角色访问权限,观察身份和资源 Allow 如何组合,并从两个方向测试显式 Deny 的优先级。禁止的写入没有改变报表字节。你在限定范围的清理前撤回了两种授权来源,并保留已准备好的身份和无关数据。请求仍获授权或意外被拒绝时,应检查全部适用策略来源。

进一步阅读 AWS 官方资料:身份策略与资源策略的评估.