前言
在一些应用场景中,我们不希望S3桶中的文件被公开访问,这时我们可以通过S3的预签名URL来限制文件的访问
但是我们又希望借助于Cloudfront的全球边缘网络,来加速S3文件的访问和上传,此时我们可以借助于Cloudfront的预签名URL,来限制对 Amazon S3 源的访问
将 CloudFront 与作为源的 Amazon S3 存储桶结合使用时,可以按提供以下好处的方式配置 CloudFront 和 Amazon S3:
限制对 Amazon S3 存储桶的访问,使其无法公开访问
确保查看者(用户)只能通过指定的 CloudFront 分配访问存储桶中的内容,也就是说,防止他们直接访问存储桶中的内容,或者通过意外的 CloudFront 分配访问存储桶中的内容
为此,请将 CloudFront 配置为向 Amazon S3 发送经过身份验证的请求,并将 Amazon S3 配置为仅允许访问来自 CloudFront 的经过身份验证的请求。
CloudFront 提供两种向 Amazon S3 源发送经身份验证的请求的方式:源访问控制 (OAC) 和源访问身份 (OAI)。我们建议使用 OAC,因为它支持:
AWS 区域 中的所有 Amazon S3 存储桶,包括 2022 年 12 月之后推出的选择加入区域
Amazon S3 使用 AWS KMS 的服务器端加密 (SSE-KMS)
对 Amazon S3 的动态请求(
PUT和DELETE)
OAI 不适用于前面列表中的场景,或者在这些场景中需要额外的解决方法。以下主题介绍了如何将 OAC 与 Amazon S3 源配合,通过Cloudfront预签名URL来限制S3文件的访问和上传
配置S3桶
在创建S3桶时,我们在S3桶的权限-->对象所有权这里,设置禁用ACL(默认创建的S3桶就是已禁用状态)
创建Cloudfront密钥组
要使用Cloudfront预签名,就需要首先在Cloudfront中创建密钥组
创建公有/私有密钥对
在Linux中,我们通过以下示例命令使用 OpenSSL 生成长度为 2048 位的 RSA 密钥对,并将其保存到名为 private_key.pem 的文件中。
openssl genrsa -out private_key.pem 2048
生成的文件同时包含公有密钥和私有密钥。以下示例命令从名为 private_key.pem 的文件中提取公有密钥。
openssl rsa -pubout -in private_key.pem -out public_key.pem
通过执行如下命令,我们记录下公有密钥的内容,稍后在以下过程中上传公有密钥(在 public_key.pem 文件中)
cat public_key.pem
将公有密钥上传到CloudFront
在Cloudfront中,我们选择密钥管理-->公有密钥-->创建公有密钥:
在创建公有密钥部分,复制public_key.pem的内容,并创建完成
将公有密钥添加到CloudFront密钥组
在Cloudfront中,我们选择密钥管理-->密钥组-->创建密钥组:
在创建密钥组中,我们选择刚刚创建的公有密钥,完成密钥组的创建
创建Cloudfront分配
在创建cloudfront分配时,在源域处,选择我们刚创建好的S3桶
在来源访问那里,我们选择 来源访问控制设置(推荐)
在来源访问控制那里,选择创建控制设置,在弹出的对话框中,选择创建控制设置:
继续后续查看器的设置:
1)要上传文件,在允许HTTP方法中,选择GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
2)选择限制查看器访问为“Yes”,并添加上述步骤中创建的密钥组
配置S3桶策略
在Cloudfront创建完成之后,会在Cloudfront抬头有个提示,其说明是需要在S3桶中配置策略
我们点击右上角的,复制策略选项,然后在S3桶中选择编辑存储桶策略:
在存储桶策略中复制策略,因为我们还需要上传文件到S3,因此修改策略,并在Action中修改添加 "s3:PutObject" 如下所示:
测试Cloudfront预签名
测试访问S3桶中文件
我们在S3桶中上传一个demo.txt文件之后,通过Cloudfront域名来访问会有如下的报错:
此时通过使用AWS CLI产生Cloudfront signed URL , 参考链接:AWS CLI command Reference - Sign - https://docs.aws.amazon.com/cli/latest/reference/cloudfront/sign.html
示例命令行如下 (这里使用的密钥ID是您在创建Cloudfront密钥组中创建的)
aws cloudfront sign --url https://d1gosm0f4h71d5.cloudfront.net/demo.txt --key-pair-id KDLJSALDHA --private-key file://private_key.pem --date-less-than 2022-12-20
执行如上命令之后,会返回一长串的 signed URL,我们直接在浏览器中访问,就可以访问到demo.txt文件
https://d1gosm0f4h71d5.cloudfront.net/demo.txt?Expires=1671494400&Signature=ZlSrvrl5mTZ9e3zk197jUqEquVLRFZ58VycKVzZeMBkbpaH72sTgrN9D7CiZ-AnsI7aMOyPgwz0KwiqjDWP98d~OhT6G5jX~H0sPyFLyMWOHnR4O7HHV9jWfR329WOwkuYGHG2-B63D-2bYlNGQX3hZV-ytGMHIFa6~u27erFzAu8kj8rISxZcdaZCWjsjp-4CLwhC4MAnID3OVe2Cp6SVaIN6AxUCt1oXbPIx-xs4tRCoJN0y-fi4RCA4CimmH-D2tKNBp0wjcagbl5oXhIFyl9BeQwJdXHxImd4oHQVILb1-4c4NYQGybRV1ihaEybzCButAk5yuGNoKwfHmn8AQ__&Key-Pair-Id=K2VLR86EMHYZD4
以上是通过AWS CLI产生Cloudfront signed URL的示例,如果想通过其他开发语言生成Cloudfront signed URL,可参考如下文档:
测试上传文件到S3桶
首先登录到EC2 Linux中,我们创建一个测试的signed_URL.txt文件,在里面随便写一些内容,然后保存:
[ec2-user@ip-10-0-0-193 cloudfront]$ vi signed_URL.txt
然后通过AWS CLI命令,为此文件生成一个Cloudfront signed URL:
aws cloudfront sign --url https://d1gosm0f4h71d5.cloudfront.net/signed_URL.txt --key-pair-id K2VLR86EMHYZD4 --private-key file://private_key.pem --date-less-than 2022-12-20
执行上述命令之后,会产生一个signed URL,然后我们结合curl命令,通过PUT请求,拼接成一条curl命令,将本地的signed_URL.txt文件上传到S3桶中:
curl -X PUT -T "signed_URL.txt" "https://d1gosm0f4h71d5.cloudfront.net/signed_URL.txt?Expires=1671494400&Signature=GWgte9kcT0-c1kN1wEaYTPEbj4zOsBohdiTPnS4B10NuR-eFbFanYhyK66E94r4DtWl5BY3Mq3U9ljOZfJjPL0bD4-ho4d4CYktS0xJCVB2j7hsuf1qf4q2dlclfSSTVNvVkLpTZC38qOS19B991O5Rbbvqs-f0LJpCJ3Xop-Ndk-jEMRTMk~wR73xsooMszMfHEJgVFb-Jvb7JBO2sn4E681WOOUqGrte-K8nJZU0boRa0LxemFwTm2U37stOD2792uJYMcy2FQ2Zh76zFkQVjsTMURiWbajoFue9ggXhrw8RY5UJ3wb8V8kwsbXViIttBEEAleoj8vfNlWfd~n5Q__&Key-Pair-Id=K2VLR86EMHYZD4"
此时我们在S3桶中,就可以看到刚刚上传的文件:













