为实例角色授予 S3 访问权限

AWSBeginner
立即练习

简介

你的 EC2 应用需要从 S3 读取一份报告。你将通过实例配置文件为应用赋予 IAM 角色,验证它确实读取了报告,并观察撤销权限后会发生什么。

你应当了解 EC2 启动、User Data 和基本 IAM 策略。这个全新环境提供应用镜像、网络、密钥对,以及包含模拟数据的 S3 存储桶。你将创建应用实例及其授权资源。

认证备考关联

本实验练习最小权限与工作负载角色,有助于理解 AWS Certified Cloud Practitioner 安全目标中的任务 2.3,以及计算目标中的任务 3.3。

启动没有角色的应用

本步骤中,你将启动报告服务器,并观察应用目前无法读取 S3 的状态。

在工作目录中开始,加载提供的镜像、网络和报告存储桶 ID:

cd /home/labex/project
source launch.env

查看提供的启动脚本。它配置了应用的 S3 存储桶和对象键,但没有提供凭证:

cat role-user-data.sh

使用这份配置启动名为 role-server 的服务器:

aws ec2 \
  run-instances \
  --image-id "$AMI_ID" \
  --instance-type t3.micro \
  --subnet-id "$SUBNET_ID" \
  --security-group-ids "$SECURITY_GROUP_ID" \
  --key-name report-key \
  --count 1 \
  --user-data file://role-user-data.sh \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=role-server}]'

保存其 ID:

INSTANCE_ID=$(aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=role-server \
  --query 'Reservations[0].Instances[0].InstanceId' \
  --output text)
aws ec2 \
  wait instance-running \
  --instance-ids "$INSTANCE_ID"

打开 AWS View,点击 Refresh resources,选择 role-server,再点击 Check application。确认返回 HTTP 200 和 Role report server。然后点击 Read S3 report。应当返回 HTTP 503 和 Application storage unavailable,因为正在运行的应用尚无角色凭证。

EC2 上的应用可以通过实例元数据获取已分配角色的临时凭证。AWS SDK 使用这些凭证为 API 请求签名。官方 EC2 角色指南解释了这个流程。你将配置角色,而不是把终端凭证复制给应用。

通过实例配置文件授予访问权限

本步骤中,你将创建角色的信任策略和权限策略,将角色放入实例配置文件,再与服务器关联。

信任策略定义谁可以代入角色。创建一份信任 EC2 服务的 JSON 策略。带引号的 here-document 分隔符会让 JSON 按原样保留:

cat > ec2-trust.json <<'JSON'
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "ec2.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}
JSON

使用该信任策略创建角色 report-reader:

aws iam \
  create-role \
  --role-name report-reader \
  --assume-role-policy-document file://ec2-trust.json

权限策略定义代入角色后可以执行哪些操作。这个应用只需要对 report.csv 执行 s3:GetObject。对象 ARN 包含存储桶和对象键。与前面带引号的 here-document 不同,下面未加引号的 JSON 分隔符会将 $REPORT_BUCKET 展开为环境提供的存储桶名称:

cat > read-report.json <<JSON
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::$REPORT_BUCKET/report.csv"
  }]
}
JSON

查看展开后的资源 ARN:

cat read-report.json

将这个内联策略添加到角色:

aws iam \
  put-role-policy \
  --role-name report-reader \
  --policy-name ReadReport \
  --policy-document file://read-report.json

实例配置文件(instance profile)将 IAM 角色提供给 EC2。使用 CLI 时,需要分别创建角色和实例配置文件。为便于辨认,创建同名配置文件:

aws iam \
  create-instance-profile \
  --instance-profile-name report-reader

将角色加入实例配置文件:

aws iam \
  add-role-to-instance-profile \
  --instance-profile-name report-reader \
  --role-name report-reader

将配置文件关联到现有实例,并保存关联 ID 供清理时使用:

ASSOCIATION_ID=$(aws ec2 \
  associate-iam-instance-profile \
  --instance-id "$INSTANCE_ID" \
  --iam-instance-profile Name=report-reader \
  --query 'IamInstanceProfileAssociation.AssociationId' \
  --output text)

查看关联信息:

aws ec2 \
  describe-iam-instance-profile-associations \
  --association-ids "$ASSOCIATION_ID" \
  --query 'IamInstanceProfileAssociations[].{Instance:InstanceId,State:State,Profile:IamInstanceProfile.Arn}'

确认状态为 associated,配置文件为 report-reader。刷新 AWS View 并点击 Read S3 report。应当返回 HTTP 200,并包含 period,total 和 Q1,320。应用使用 SDK 的角色凭证获取真实的 S3 对象。如果关联仍在传播,请稍等后重试请求。

该角色只允许读取一个对象,没有授予整个存储桶或管理员权限。实例配置文件指南解释了配置文件如何承载角色,以及关联变更为何可能需要时间才能传播。

观察权限撤销

本步骤中,你将移除角色的报告访问权限,并区分授权失败与应用故障。

只删除你创建的内联策略:

aws iam \
  delete-role-policy \
  --role-name report-reader \
  --policy-name ReadReport

列出角色剩余的内联策略:

aws iam \
  list-role-policies \
  --role-name report-reader

应当看到空的 PolicyNames 列表。实例配置文件仍有关联,但其中的角色已不再允许读取报告。

在 AWS View 中点击 Check application,确认 HTTP 200,说明服务器仍在运行。然后点击 Read S3 report,应当返回 HTTP 403 和 Access denied。如果权限变更尚未传播,请稍等后再次请求。健康检查正常而 S3 访问被拒绝,指向的是授权问题,而不是实例停止或应用缺失。

SDK 可能缓存临时凭证。移除角色权限会改变这些凭证允许执行的操作;移除实例配置文件并不意味着已签发凭证立即失效。

清理实例和角色

本步骤中,你将删除自己创建的关联、服务器、实例配置文件和角色。

使用已保存的关联 ID 解除配置文件关联:

aws ec2 \
  disassociate-iam-instance-profile \
  --association-id "$ASSOCIATION_ID"

终止应用实例:

aws ec2 \
  terminate-instances \
  --instance-ids "$INSTANCE_ID"
aws ec2 \
  wait instance-terminated \
  --instance-ids "$INSTANCE_ID"

从不再使用的实例配置文件中移除角色:

aws iam \
  remove-role-from-instance-profile \
  --instance-profile-name report-reader \
  --role-name report-reader

删除空的配置文件:

aws iam \
  delete-instance-profile \
  --instance-profile-name report-reader

内联策略已在撤销权限时删除。现在删除你的角色:

aws iam \
  delete-role \
  --role-name report-reader

确认实例已终止:

aws ec2 \
  describe-instances \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}'

确认指定名称的角色和实例配置文件已不存在:

aws iam \
  list-roles \
  --query "Roles[?RoleName=='report-reader'].RoleName"
aws iam \
  list-instance-profiles \
  --query "InstanceProfiles[?InstanceProfileName=='report-reader'].InstanceProfileName"

两个列表都应为 []。刷新 AWS View,确认服务器不再是运行中的目标。保留已准备的 S3 数据、网络和密钥对。

总结

你为 IAM 角色创建了 EC2 信任关系和单个 S3 对象的读取权限,通过实例配置文件将角色提供给应用,并验证了应用确实读取报告。随后你撤销权限,确认应用健康检查正常时 S3 访问仍可被拒绝。最后,你删除了实例、实例配置文件和角色。