介绍
应用需要读取存储在 S3 中的私有导出文件。你将使用客户密钥加密新上传的对象,为读取者授予访问权限,并通过实际下载测试对象权限与密钥权限的影响。
请先完成 在 S3 中存储和检索文件、使用 KMS 加密和解密私有导出文件,以及它们要求的 IAM 前置实验。本实验的全新 VM 提供模拟导出文件、读取者角色会话和独立的参考资源。
相关认证考点
本实验为以下认证考点提供动手练习。
- Cloud Practitioner (CLF-C02) · 任务 2.2: S3 静态加密与独立的对象、密钥权限。
- Solutions Architect – Associate (SAA-C03) · 任务 1.3: S3 静态加密与独立的对象、密钥权限。
- Developer – Associate (DVA-C02) · 任务 2.2: S3 静态加密与独立的对象、密钥权限。
- CloudOps Engineer – Associate (SOA-C03) · 任务 4.2: S3 静态加密与独立的对象、密钥权限。
- Security – Specialty (SCS-C03) · 任务 5.2: 基础练习:S3 静态加密与独立的对象、密钥权限。
- Data Engineer – Associate (DEA-C01) · 任务 4.3: 基础练习:S3 静态加密与独立的对象、密钥权限。
- DevOps Engineer – Professional (DOP-C02) · 任务 6.2: 基础练习:S3 静态加密与独立的对象、密钥权限。
- Solutions Architect – Professional (SAP-C02) · 任务 2.3: 基础练习:S3 静态加密与独立的对象、密钥权限。
准备加密的对象存储
本步骤中,你将创建客户 KMS 密钥,并配置一个新存储桶默认使用它。存储桶容纳对象;每个对象都有一个对象键,例如 exports/private-export.json。使用 KMS 的服务器端加密(SSE-KMS) 让 S3 使用你选择的密钥加密存储的对象。默认加密会应用于新上传的对象,无需每个客户端重复指定加密选项。
使用提供的模拟文件 private-export.json;export-reader 角色会话最初没有对象或密钥的访问权限。保留参考存储桶、对象和密钥。在 Terminal 旁打开 AWS View,对比密钥和存储桶状态、读取者授权,以及不暴露数据的字节比较结果。
先进入项目目录,确认提供的操作员身份。cd 用于切换目录;调用者查询会返回身份 ARN,而不会暴露凭证。
cd /home/labex/project
aws sts get-caller-identity --query Arn --output text
预期看到 labex-sec02-operator 用户。创建对称客户密钥和一个易读的别名。--query 选择 ARN,--output text 去除 JSON 引号,$(...) 将结果保存到 shell 变量中。
KEY_ARN=$(aws kms create-key \
--description labex-sec02-owned-export \
--query KeyMetadata.Arn \
--output text)
aws kms create-alias \
--alias-name alias/labex-sec02-private-export \
--target-key-id "$KEY_ARN"
使用带时间戳后缀的临时存储桶名称,避免名称冲突。labex-sec02-owned- 前缀可以区分你的存储桶和提供的参考存储桶。本实验使用 us-east-1,因此创建存储桶时不需要位置约束。
BUCKET="labex-sec02-owned-$(date +%s)"
aws s3api create-bucket \
--bucket "$BUCKET" \
--region us-east-1 \
--query Location \
--output text
使用精确的密钥 ARN 配置 SSE-KMS。S3 Bucket Key 可以减少重复的 KMS 请求;这里保持关闭,让每个对象使用自己的 KMS 加密上下文。将默认规则写入普通 JSON 文件。这里的 here-document 会展开 $KEY_ARN;file:// 用于加载保存的配置。
cat > bucket-encryption.json <<EOF
{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "$KEY_ARN"
},
"BucketKeyEnabled": false
}
]
}
EOF
aws s3api put-bucket-encryption --bucket "$BUCKET" \
--server-side-encryption-configuration file://bucket-encryption.json
aws s3api get-bucket-encryption \
--bucket "$BUCKET" \
--query ServerSideEncryptionConfiguration
预期看到 aws:kms、你的密钥 ARN 和 BucketKeyEnabled: false。在此 Terminal 中保留 KEY_ARN 和 BUCKET,供后续命令使用。在 AWS View 中,你创建的密钥处于启用状态,存储桶中还没有对象。
为读取者授予两项必需权限
本步骤中,你将上传导出文件,并让角色恢复其原始字节。上传需要所选密钥的 kms:GenerateDataKey 权限。SSE-KMS 使用数据密钥加密对象字节。KMS 保护该数据密钥;S3 存储加密的对象和封装后的数据密钥,然后在授权读取者下载对象时请求解密。密钥材料无需出现在 CLI 输出中。

读取这个 SSE-KMS 对象,需要同时具备对象访问权限和密钥解密权限。
使用 s3api put-object 上传提供的文件。存储桶默认配置会提供加密设置;--body private-export.json 将指定的本地文件作为对象字节读取。对于这个小型导出文件,使用此单部分上传 API。
aws s3api put-object \
--bucket "$BUCKET" \
--key exports/private-export.json \
--body private-export.json \
--query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId,BucketKey:BucketKeyEnabled}'
aws s3api head-object \
--bucket "$BUCKET" \
--key exports/private-export.json \
--query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId,Bytes:ContentLength}'
预期看到 aws:kms、你创建的密钥 ARN 和原始文件大小。仅凭元数据无法判断读取者能否解密。先只授予对象访问权限。对象 ARN 包含存储桶和对象键,与存储桶 ARN 不同。下面的 here-document 会写入策略文件,并展开其中的 $BUCKET。
cat > read-object.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::$BUCKET/exports/private-export.json"
}
]
}
EOF
aws iam put-role-policy \
--role-name labex-sec02-export-reader \
--policy-name ReadExportObject \
--policy-document file://read-object.json
使用 --profile export-reader 选择准备好的读取者会话。此次尝试必须以 AccessDenied 失败:角色可以读取这个对象,但尚未获得 KMS 解密授权。
aws \
--profile export-reader s3api get-object \
--bucket "$BUCKET" \
--key exports/private-export.json reader-export.json
只为该角色授予精确密钥的 kms:Decrypt 权限。下载不需要密钥管理权限,也不需要 kms:GenerateDataKey。
cat > decrypt-key.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "$KEY_ARN"
}
]
}
EOF
aws iam put-role-policy \
--role-name labex-sec02-export-reader \
--policy-name DecryptExportKey \
--policy-document file://decrypt-key.json
aws \
--profile export-reader s3api get-object \
--bucket "$BUCKET" \
--key exports/private-export.json reader-export.json \
--query '{Encryption:ServerSideEncryption,Key:SSEKMSKeyId}'
chmod 600 reader-export.json
cmp private-export.json reader-export.json
当字节内容一致时,cmp 不会输出任何内容,并返回成功。AWS View 此时应显示存储的密文,以及读取者的 GetObject 返回字节与提供的导出文件一致。这是两个独立的观察结果:加密存储保护静态字节,而限定范围的权限控制数据获取。

诊断权限与密钥状态导致的失败
本步骤中,你将区分缺少解密授权与密钥被禁用这两种情况。保留对象权限,让每次只改变一个条件。
移除读取者的密钥授权,然后重新下载同一个对象。角色仍然拥有 s3:GetObject,但请求必须以 AccessDenied 失败。
aws iam delete-role-policy \
--role-name labex-sec02-export-reader \
--policy-name DecryptExportKey
aws \
--profile export-reader s3api get-object \
--bucket "$BUCKET" \
--key exports/private-export.json reader-export.json
检查保留下来的对象策略。它应仍然只指定这个导出对象。
aws iam get-role-policy \
--role-name labex-sec02-export-reader \
--policy-name ReadExportObject \
--query PolicyDocument
恢复精确密钥授权,并禁用你的密钥。被禁用的密钥仍然存在,但不能执行密码学操作。不要更改无关的参考密钥。
aws iam put-role-policy \
--role-name labex-sec02-export-reader \
--policy-name DecryptExportKey \
--policy-document file://decrypt-key.json
aws kms disable-key --key-id "$KEY_ARN"
aws \
--profile export-reader s3api get-object \
--bucket "$BUCKET" \
--key exports/private-export.json reader-export.json
预期出现密钥被禁用导致的失败。拥有 IAM 权限也不能让被禁用的密钥变得可用。确认其原生状态,然后启用密钥并再次获取对象。
aws kms describe-key --key-id "$KEY_ARN" --query KeyMetadata.KeyState --output text
aws kms enable-key --key-id "$KEY_ARN"
aws \
--profile export-reader s3api get-object \
--bucket "$BUCKET" \
--key exports/private-export.json reader-export.json \
--query ServerSideEncryption \
--output text
chmod 600 reader-export.json
cmp private-export.json reader-export.json
预期看到 aws:kms,且比较成功。AWS View 会同时保留失败请求与成功恢复的记录,而参考存储桶和密钥仍然可用。
下载失败后,旧的本地文件可能仍然存在,因此仅凭文件存在不能证明请求成功;经过签名的读取请求与比较结果才能证明恢复成功。
移除自己创建的资源并安排删除密钥
本步骤中,你将清理指定的导出资源。先完成前面的功能检查。S3 存储桶必须清空后才能删除;客户 KMS 密钥需要经过删除等待期,不会立即消失。
只删除你指定的导出对象,然后删除其存储桶。成功列出资源清单,确认你的 $BUCKET 已不存在,而 labex-sec02-reference 仍然保留。
aws s3api delete-object --bucket "$BUCKET" --key exports/private-export.json
aws s3api delete-bucket --bucket "$BUCKET"
aws s3api list-buckets --query 'Buckets[].Name'
移除你添加的两项权限和自己创建的别名。提供的读取者角色是会话配套资源;不要删除它或无关的参考资源。
aws iam delete-role-policy \
--role-name labex-sec02-export-reader \
--policy-name ReadExportObject
aws iam delete-role-policy \
--role-name labex-sec02-export-reader \
--policy-name DecryptExportKey
aws iam list-role-policies --role-name labex-sec02-export-reader --query PolicyNames
aws kms delete-alias --alias-name alias/labex-sec02-private-export
使用最短的七天等待期安排删除你的密钥,然后读取其原生状态。安排删除会立即使密钥不可用,但不能证明密钥已经被删除。
aws kms schedule-key-deletion \
--key-id "$KEY_ARN" \
--pending-window-in-days 7 \
--query DeletionDate \
--output text
aws kms describe-key --key-id "$KEY_ARN" --query KeyMetadata.KeyState --output text
aws kms describe-key \
--key-id alias/labex-sec02-reference \
--query KeyMetadata.KeyState \
--output text
预期你的密钥为 PendingDeletion,参考密钥为 Enabled。移除指定的本地文件;这些命令不会影响无关的项目文件。
rm -f private-export.json reader-export.json read-object.json decrypt-key.json bucket-encryption.json
在移除临时 CLI 配置档之前,运行本步骤的验证。成功的原生资源清单查询才能证明清理完成,身份验证错误不能作为清理证据。
rm -f /home/labex/.aws/credentials /home/labex/.aws/config
unset KEY_ARN BUCKET
总结
你将 SSE-KMS 配置为存储桶默认加密方式,上传了加密导出文件,并通过权限范围限定为一个对象和一把密钥的角色恢复了原始字节。撤销 kms:Decrypt 和禁用密钥都会阻止读取,而无需更改对象授权。你恢复了访问,只删除自己创建的 S3 资源,并安排删除自己创建的 KMS 密钥,同时保留参考存储桶和密钥。



