Cloudfront 如何分发 AWS KMS 密钥以获取静态加密的 S3 图像?

How can a Cloudfront distribution an AWS KMS key to GET an S3 image encrypted at rest?

我想使用 AWS 的服务器端加密 (SSE)AWS 密钥管理服务 (KMS) 来加密数据在 S3 休息。 (请参阅此 AWS blog post 详细介绍 SSE-KMS。)

但是,我也有使用 Cloudfront 预签名 URL 的要求。

如何设置 Cloudfront 分配以使用 AWS KMS 中的密钥解密和使用静态加密的 S3 对象?

This Boto3 issue 好像有人在找和我一样的答案,但是没有结果)。

使用 S3 预签名 URL。这篇 AWS 文章讨论了如何使用 Java 生成 url,但这很容易移植到另一种语言。

Server-Side Encryption with AWS Key Management Service (SSE-KMS)

这在以前是不可能的,因为 CloudFront 不支持它 因为(正如我在对 John 的回答的评论中提到的——这是在正确的轨道上)没有roll-your-own 使用 Lambda@Edge 解决方案的方法,因为 X-Amz-Cf-Id 请求 header——在 CloudFront 的背面生成并且仅对 S3 可见,而不对触发器调用——将使任何无效您尝试添加到 Lambda@Edge 触发器内的请求的签名,因为所有 X-Amz-* header 的签名是强制性的。

但是 X-Amz-Cf-Id header 值现在暴露给事件结构中的 Lambda@Edge 触发器函数——不是通过其他请求 headers,而是作为一个简单的字符串属性 -- 在 event.Records[0].cf.config.requestId.

有了这个值,您可以在 Lambda@Edge 环境中使用执行角色凭据和 built-in SDK 生成签名并添加必要的 header(包括Authorization header 与派生的凭据标识符和 freshly-generated 签名) 到请求。

此设置不使用源访问标识符 (OAI),因为使用 Lambda@Edge 触发器的 IAM 执行角色而不是 OAI 来说服 S3 请求已获得授权。

Achraf Souk 发布了官方 AWS 博客post从头到尾解释了解决方案。

https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/

以下设置适用于我们:

在您的应用程序中,生成 Cloudfront 可以验证的签名 URL (https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html)。

您不使用 OAI,而是根据以下内容创建 Lambda@Edge 源请求函数:https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/

请注意,如果您的存储桶包含“.” (我们有),JS 代码中有一个错误,可以通过以下方式缓解:

// Infer the region from the host header
// const region = options.host.split('.')[2];

const hostArr = options.host.split('.');
const region = hostArr [hostArr.length - 3];

最后,我们添加了一个原始响应 Lambda@Edge 来清除我们不想暴露的 headers。 Esp 包含 AWS 账户 ID 的 X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id。

最后,我想对上面的 statement/comment 发表评论,Lamda@Edge 响应主体限制为 1 MB,这仅适用于生成的内容(或修改后的内容,如果您包含 body ) 通过 lambda 函数。 当使用上面的 Lambda@Edge 函数时,来自 S3 源的响应没有这样的限制,我们正在服务 objects >> 1MB(通常 100+ MB)。