绕过 x-amz-cf-id header 包含在云端 S3 身份验证中的需要
Bypassing need for x-amz-cf-id header inclusion in S3 auth in cloudfront
我有一个不完全正统的 CF->S3 设置。这里的相关组件是:
Cloudfront 分布 origin s3.ap-southeast-2.amazonaws.com
添加 S3 授权(版本 2)查询字符串(使用函数使用的 S3 策略签名)的 Lambda@Edge 函数(原始请求)。
Lambda返回的请求完全正确。如果我记录 uri、主机和查询字符串,我会得到我请求的文件。但是,如果我直接通过 Cloudfront link 访问它,请求将失败,因为它不再使用 AWSAccessKeyID
,而是选择使用 x-amz-cf-id
(但使用相同的签名,Amz-Security-Token 等)。 更正:它可能不会取代,但除此之外还需要。
我知道是这种情况,因为我已经退回了
StringToSign
和 SignatureProvided
。除了 AWSAccessKeyID
已替换为 x-amz-cf-id
.
之外,它们都与 Lambda 响应匹配
这显然是一个非常具体的问题。我可能不得不考虑重塑这个架构,但我不想这样做。有几个要求让我失望了这个不完全正常的设置。
因此,对于身份验证 V2 或 V4,附加到原始请求且 Lambda@Edge 原始请求函数无法访问的 x-amz-cf-id
header 似乎必须包含在身份验证字符串中。这是不可能的。
简单的解决方案是使用 Cloudflare 中的 built-in S3 集成,如果像我一样使用 Lambda@Edge 源请求函数来切换存储桶,这就是您想要的目标。对于您要使用的每个存储桶,添加以下策略以允许您的 CF 分发访问存储桶中的 objects。
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <CloudfrontID>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<bucket-name>/*"
}
]
}
CloudfrontID
是指 Origin Access Identity 下的 ID,而不是 Amazon S3 Canonical ID .
我相信 AWSAccessKeyID
=> x-amz-cf-id
替换是两种机制的结果:
首先,您需要配置 CloudFront 以将查询参数转发到源。否则,它将去除所有参数。如果您使用 S3 签名 URL,请确保还基于所有参数进行缓存,否则您最终将没有任何访问控制。
其次,CloudFront 将 x-amz-cf-id
附加到不去往 S3 源 的请求 。您可以在 CloudFront 控制台仔细检查源类型,您需要确保它被报告为 S3。我有一个 blog post 详细描述它。
但是使用 Lambda@Edge 向所有请求添加 S3 签名达不到目的。如果您想将存储桶保密并只允许 CloudFront 访问它,那么请使用 Origin Access Identity,这正是该用例。
X-amz-cf-id 是 CF 的保留头,可以通过事件获取,如 event['Records'][0]['cf']['config' ]['requestId']。您不必使用 X-amz-cf-id 计算 Authentication V4。
我有一个不完全正统的 CF->S3 设置。这里的相关组件是:
Cloudfront 分布
origin s3.ap-southeast-2.amazonaws.com
添加 S3 授权(版本 2)查询字符串(使用函数使用的 S3 策略签名)的 Lambda@Edge 函数(原始请求)。
Lambda返回的请求完全正确。如果我记录 uri、主机和查询字符串,我会得到我请求的文件。但是,如果我直接通过 Cloudfront link 访问它,请求将失败,因为它不再使用 AWSAccessKeyID
,而是选择使用 x-amz-cf-id
(但使用相同的签名,Amz-Security-Token 等)。 更正:它可能不会取代,但除此之外还需要。
我知道是这种情况,因为我已经退回了
StringToSign
和 SignatureProvided
。除了 AWSAccessKeyID
已替换为 x-amz-cf-id
.
这显然是一个非常具体的问题。我可能不得不考虑重塑这个架构,但我不想这样做。有几个要求让我失望了这个不完全正常的设置。
因此,对于身份验证 V2 或 V4,附加到原始请求且 Lambda@Edge 原始请求函数无法访问的 x-amz-cf-id
header 似乎必须包含在身份验证字符串中。这是不可能的。
简单的解决方案是使用 Cloudflare 中的 built-in S3 集成,如果像我一样使用 Lambda@Edge 源请求函数来切换存储桶,这就是您想要的目标。对于您要使用的每个存储桶,添加以下策略以允许您的 CF 分发访问存储桶中的 objects。
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <CloudfrontID>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<bucket-name>/*"
}
]
}
CloudfrontID
是指 Origin Access Identity 下的 ID,而不是 Amazon S3 Canonical ID .
我相信 AWSAccessKeyID
=> x-amz-cf-id
替换是两种机制的结果:
首先,您需要配置 CloudFront 以将查询参数转发到源。否则,它将去除所有参数。如果您使用 S3 签名 URL,请确保还基于所有参数进行缓存,否则您最终将没有任何访问控制。
其次,CloudFront 将 x-amz-cf-id
附加到不去往 S3 源 的请求 。您可以在 CloudFront 控制台仔细检查源类型,您需要确保它被报告为 S3。我有一个 blog post 详细描述它。
但是使用 Lambda@Edge 向所有请求添加 S3 签名达不到目的。如果您想将存储桶保密并只允许 CloudFront 访问它,那么请使用 Origin Access Identity,这正是该用例。
X-amz-cf-id 是 CF 的保留头,可以通过事件获取,如 event['Records'][0]['cf']['config' ]['requestId']。您不必使用 X-amz-cf-id 计算 Authentication V4。