概括
我有一个在 AWS 中运行的平台,它通过 AWS Lambda 支持的 REST API 公开。该平台将元数据存储在 DynamoDB 中,将内容存储在 S3 中。用户由 Cognito 进行身份验证并存储在用户池中。该平台管理权限以控制哪些用户可以访问(以及他们是否可以修改)哪些元数据(以及相关的内容)。
我可以使用 STS 将用户的 JWT 令牌交换为 STS 令牌(使用 Cognito 身份池),并授予他们读取或写入 S3 中特定对象的权限。创建 STS 令牌由平台处理。这在直接访问 S3 时非常有效,并且似乎是 STS 的完美用例。
两个旁白来解决一些评论:
- 预签名的 S3 URL 不够安全,因为知道链接的任何人都可以访问内容
- 我必须直接上传到 S3,因为我没有运行任何服务器,并且由于 Lambda 中的临时空间限制 (512MB) 和请求可以通过 API 网关执行的时间量,Lambda 不适合流式传输我的内容(29 秒)
我想在 S3 存储桶前面添加 CloudFront 以从其 CDN 功能中受益;如果可以从边缘提供内容而不是每次都从 S3 检索,这将降低数据传输成本。这是我遇到问题的地方 - 我不知道如何将 STS 令牌发送到 CloudFront,以便它将它传递给 S3。
问题:当 S3 存储桶位于 CloudFront 前端时,如何使用 STS 凭证从 S3 存储桶中读取/写入?
更多详细信息
我创建了两个可以由 STS 承担的角色。一个有s3:ListBucket
,一个有s3:PutObject
。然后,我使用 Postman 在我的存储桶上执行GET
和请求,从 STS调用PUT
中指定访问密钥、密钥和会话令牌。assume-role-with-web-identity
GET
直接访问 S3 时,和操作和两者PUT
都有效,但在使用 CloudFront 时均无效。有趣的是,我得到不同的错误GET
和PUT
。
错误来自GET
:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>No AWSAccessKey was presented.</Message>
<RequestId><!-- snip --></RequestId>
<HostId><!-- snip --></HostId>
</Error>
错误来自PUT
:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId><!-- snip --></AWSAccessKeyId>
<StringToSign><!-- snip --></StringToSign>
<SignatureProvided><!-- snip --></SignatureProvided>
<StringToSignBytes><!-- snip --></StringToSignBytes>
<CanonicalRequest><!-- snip --></CanonicalRequest>
<CanonicalRequestBytes><!-- snip --></CanonicalRequestBytes>
<RequestId><!-- snip --></RequestId>
<HostId><!-- snip --></HostId>
</Error>
我已经从回复中删除了一些值,但如果有必要可以提供它们。