介绍
一个运行中的应用需要读取私有报告。你将通过 Terraform 引用连接 IAM 角色和实例配置文件,授予目标对象的访问权限,并在移除权限前后测试应用的实际请求。
本实验要求你了解 Terraform 引用和 EC2 部署,以及 AWS 角色信任、实例配置文件和范围限定的 S3 权限。全新环境提供运行中的应用、其网络、私有报告存储桶和一个无关的参考应用。你将保持提供的数据和参考环境完整不变。
与认证考试的关联
| 认证 | 考试任务 | 实践内容 |
|---|---|---|
| Cloud Practitioner (CLF-C02) | 任务 2.3 | IAM 角色和最小权限对象访问。 |
| Solutions Architect – Associate (SAA-C03) | 任务 1.1 | 通过范围限定的权限实现基于角色的工作负载访问。 |
| CloudOps Engineer – Associate (SOA-C03) | 任务 4.1 | 基础 IAM 角色和策略实现。 |
实验概览

为运行中的应用赋予角色身份
在这一步中,你将定义 EC2 角色和实例配置文件,将配置文件附加到提供的应用,并观察实际生效的工作负载身份。
上方的 AWS View 显示与 Terminal 查询相同的资源。其 Request path 选择器可请求应用健康状态、工作负载身份或两个私有对象中的任意一个。Terminal 使用预先准备的操作者身份;应用使用自己的实例角色。操作者查询成功并不能证明应用具有权限。
检查已准备好的根目录并记录实例 ID:
cd /home/labex/project/application-reports
cat terraform.tfvars.json
cat application.tf
terraform state list
INSTANCE_ID=$(terraform output -raw instance_id)
echo "$INSTANCE_ID"
REPORT_BUCKET=$(terraform output -raw report_bucket)
echo "$REPORT_BUCKET"
现有状态管理应用实例。网络、AMI、存储桶和参考应用均单独提供。User Data 已将应用指向预先准备的存储桶中的 report.csv,但不包含访问密钥。
在 AWS View 中,选择 application-server、User · 198.51.100.10、Application · 8081 和 Health,然后点击 Send request。预期看到 Connected · 200 和 Report application。选择 Private report 并再次发送请求。应用尚无法读取报告,会返回 Connected · 503 和 Application storage unavailable:HTTP 应用可以访问,但它没有工作负载凭据。
IAM 角色的信任策略控制谁可以承担该角色。实例配置文件将角色连接到 EC2。两者单独都不会授予读取 S3 对象的权限。创建这两个资源:
cat > identity.tf <<'HCL'
resource "aws_iam_role" "reports" {
name = "tf-report-reader"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_instance_profile" "reports" {
name = "tf-report-reader"
role = aws_iam_role.reports.name
}
HCL
sed -i '/vpc_security_group_ids/a\ iam_instance_profile = aws_iam_instance_profile.reports.name' application.tf
terraform fmt
terraform validate
terraform plan
sed 命令在现有安全组属性之后插入实例配置文件属性。该资源引用将运行中的实例连接到配置文件,配置文件再引用角色。审查计划:创建角色和配置文件,更新现有实例的关联,不替换实例或更改 User Data。
应用配置并输入 yes:
terraform apply
检查原生关联和实例配置文件:
aws ec2 \
describe-iam-instance-profile-associations \
--filters "Name=instance-id,Values=$INSTANCE_ID" \
--query 'IamInstanceProfileAssociations[].{Instance:InstanceId,State:State,Profile:IamInstanceProfile.Arn}'
aws iam \
get-instance-profile \
--instance-profile-name tf-report-reader \
--query 'InstanceProfile.{Name:InstanceProfileName,Roles:Roles[].RoleName}'
在 AWS View 中,为 application-server 选择 Workload identity 并发送请求。预期看到 Connected · 200 和包含 assumed-role/tf-report-reader/ 的 ARN。这来自实例内部使用临时角色凭据调用的 STS,而不是 Terminal 操作者。
选择 Private report 并再次发送。预期看到 Connected · 403 和 Access denied。角色身份现在已正常工作,但尚无对象读取权限。这是预期的授权失败。
仅授予目标报告的访问权限
在这一步中,你将为应用角色授予一项对象读取权限,并测试允许的报告和一个无关私有对象。
角色的权限策略决定其会话能够执行哪些操作。使用身份策略,仅允许对确切的 report.csv ARN 执行 s3:GetObject。存储桶名称来自提供的输入;角色来自资源引用。User Data 中不应放入任何静态凭据。
cat > permissions.tf <<'HCL'
resource "aws_iam_role_policy" "report" {
name = "ReadApplicationReport"
role = aws_iam_role.reports.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject"]
Resource = ["arn:aws:s3:::${var.report_bucket}/report.csv"]
}]
})
}
HCL
terraform fmt
terraform validate
terraform plan
计划新增一个策略。它不得替换应用或创建新存储桶。应用配置并输入 yes:
terraform apply
在 AWS View 中,保持选择 application-server、User 和端口 8081。选择 Private report 并发送请求。预期看到 Connected · 200,报告内容为:
period,total
Q1,320
选择 Unrelated private object 并再次发送请求。预期看到 Connected · 403 和 Access denied。应用可以读取自己的报告,而 private.csv 仍在授权范围之外。此 403 是已连接到的应用返回的实际 S3 授权结果,并非网络连接失败。
返回 Workload identity 并再次发送。其 ARN 必须仍标识工作负载角色。确认收敛:
terraform plan
预期看到 No changes.。

撤销权限并测试实际效果
在这一步中,你将仅移除读取策略,并证明拥有有效角色身份的运行中应用不再具有报告访问权限。
移除权限不同于分离实例配置文件或停止实例。保留角色和配置文件,删除策略资源配置,然后审查删除计划:
rm permissions.tf
terraform plan
预期销毁读取策略,不替换实例。应用配置并输入 yes:
terraform apply
独立读取剩余内联策略名称:
aws iam \
list-role-policies \
--role-name tf-report-reader \
--query PolicyNames
预期看到 []。在 AWS View 中,向应用发送 Workload identity 请求。它仍返回 Connected · 200 和相同角色名称。然后发送 Private report 和 Unrelated private object 请求。两者都必须返回 Connected · 403 和 Access denied。尽管应用和角色关联仍存在,被拒绝的读取证明移除权限确实影响了实际工作负载请求。
terraform plan
预期看到 No changes.。
删除受管理资源并保留提供的数据
在这一步中,你将移除受管理的实例、实例配置文件和角色,同时保留外部报告存储桶、其中的对象和参考环境。
策略已移除。审查剩余删除范围:
terraform plan -destroy
预期包含三个受管理资源:应用实例、实例配置文件和 IAM 角色。然后销毁它们,并输入 yes:
terraform destroy
同一个实例必须在原生查询中显示已终止:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name}'
terraform state list
预期看到 terminated,且状态中没有受管理资源。使用确切名称查询角色和实例配置文件列表;成功返回的空列表可证明它们已不存在,不能把身份验证失败当作清理完成:
aws iam list-roles --query "Roles[?RoleName=='tf-report-reader'].RoleName"
aws iam list-instance-profiles --query "InstanceProfiles[?InstanceProfileName=='tf-report-reader'].InstanceProfileName"
两者都返回 []。存储桶在此状态之外提供。使用 Terminal 操作者读取两个保留对象并检查字节。这些操作者读取用于检查数据保留;应用的限定访问已另行通过其角色进行测试。
aws s3api get-object --bucket "$REPORT_BUCKET" --key report.csv /tmp/retained-report.csv
cat /tmp/retained-report.csv
aws s3api get-object --bucket "$REPORT_BUCKET" --key private.csv /tmp/retained-private.csv
cat /tmp/retained-private.csv
报告仍为 period,total / Q1,320;无关对象仍为 private,retained。在 AWS View 中,选择 reference-server、User、Application · 8081 和 Health,然后发送请求。预期看到 Connected · 200 和 Reference application。
保留 Terraform 文件以供审阅。之后的普通计划会提出重新创建仍由配置定义的资源;成功销毁不要求删除这些配置。
总结
你通过 Terraform 引用将应用实例连接到角色,区分了角色身份与对象权限,并测试了私有报告读取成功和无关对象访问拒绝。随后,你撤销授权,观察到实际授权失败,并移除了受管理资源,同时保留提供的数据和参考应用。



