Tag: Amazon CloudFront


使用Amazon CloudFront签名URL+S3实现私有内容发布

前言

Amazon CloudFront 是一个全球性内容分发网络 (CDN),可实现网站、API、视频内容或其他 Web 资产的快速分发。用户可以使用CloudFront来加速分发保存在Amazon S3存储桶上的各种内容,比如文档、图片、媒体文件和软件安装包等。很多AWS客户在使用CloudFront+S3通过互联网向自己的最终用户提供内容下载的时候,也希望能够限制到只允许合法的用户下载,比如那些已经通过了身份认证或已经付费的用户,避免开放下载可能造成的数据安全和流量成本等问题。进一步,这些AWS客户还希望能够限制其最终用户可以执行下载操作的日期时间段,发起下载请求的来源IP地址范围等等。使用CloudFront的签名URL功能就可以帮助AWS客户实现其私有内容的安全发布。

CloudFront签名URL功能简介

CloudFront的签名URL功能通过在普通的Http或Https请求中添加经过哈西和签名认证的策略内容,来保护私有内容不受非法访问。当收到来自客户端比如浏览器、移动App或桌面应用对特定资源的访问请求后,CloudFront会首先利用保存的密钥解密请求中包含的签名部分内容,检查是否完整和正确。然后CloudFront继续分析解密出的权限策略内容,并根据权限策略定义的限制条件来决定是否向客户端提供请求资源。

AWS客户可以开发Web服务或工具软件来向自己的最终用户提供签名URL,就可以让这些最终用户在受限的条件下安全地访问通过CloudFront发布的内容,比如存储在S3中的图片。

AWS客户除了可以在签名URL的权限策略定义中直接限制资源请求客户端可以访问的资源种类、请求发生时间、来源IP地址范围以外,结合CloudFront既有功能还可以进一步限制其发出请求的协议类型(Http或Https)、访问域名类型(CloudFront自动分配域名或客户自有域名)。

整体技术方案

需求

在正式开始创建CloudFront私有内容发布之前,我们首先要明确在创建过程中的一些主要的选项。对于这些选项的不同设置会影响最终所创建的私有内容发布的效果。好在通过CloudFront发布私有内容的主要步骤基本类似,通过了解一个典型的CloudFront私有内容发布的完整过程就可以快速理解和掌握其他方式的发布过程。下面的表格列出了几个主要可选项和我们本次演示所做的选择。

 

选项 值域 本次选择
源站类型

S3存储桶,

普通Web服务器

S3存储桶
客户端到CloudFront的协议类型

Http,

Https

Https
CloudFront到源站的协议类型

Http,

Https

Https
CloudFront发布点的类型

Web发布点,

RTMP发布点

Web发布点
CloudFront发布点的域名类型

CloudFront自动分配的域名,

客户自有域名

客户自有域名
签名类型

签名URL,

签名Cookie

签名URL
权限策略类型

Canned Policy,

Custom Policy

Custom Policy

架构

一般地,一个完整的高性能私有内容发布平台主要包括四部分:内容源站,加速CDN,身份认证和权限管理,资源请求客户端。基于上面的需求分析,我们可以明确本次介绍中的四部分组成:

  • 内容源站:S3存储桶
  • 加速CDN:CloudFront
  • 身份认证和权限管理:签名URL生成器

说明:这次功能演示并没有包括用户身份认证部分。这部分功能读者可以基于基本的签名URL生成器功能基础上继续添加。比如开发一个Web服务,在最终用户请求某个资源的时候先校验其身份,要求其先输入正确的用户名和密码,然后再为请求的具体资源自动产生签名URL并返回请求客户端。

  • 资源请求客户端:用户浏览器,移动APP或桌面客户端应用


演示

当我们完成本次CloudFront签名URL+S3实现私有内容发布的相关设置和开发后,具体的演示过程如下:

1)   向S3存储桶上传需要发布的内容,比如图片文件或视频文件。

2)  利用签名URL生成器为上传的资源产生签名URL

3)  在测试机的浏览器中输入签名URL并发送请求给CloudFront

4)  CloudFront验证签名URL

5)  如果被请求资源已经在CloudFront当前边缘节点的缓存中,直接返回被请求资源。

6)  如果被请求资源还不在CloudFront当前边缘节点的缓存中:

a) CloudFront从S3存储桶取回被请求资源

b)  CloudFront将被请求资源返回浏览器

c)  CloudFront在当前边缘节点缓存该资源

使用CloudFront签名URL+S3实现私有内容发布的完整步骤

完整的步骤将分为以下几个主要部分分别执行:

(一) 创建CloudFront密钥对

(二) 创建S3存储桶

(三) 上传SSL安全证书

(四) 创建CloudFront Web发布点

(五) 更新 CloudFront Web 发布点,启用签名URL功能

(六) 开发签名URL生成器

(七) 验证测试

(一)创建CloudFront密钥对

1.  使用AWS 根账号登录Global AWS Web控制台

2.  访问“服务”→“安全、身份与合规”→“IAM”

3.  查看“安全状态”,点开“删除您的根访问密钥”,执行“管理安全证书”

4.  访问“CloudFront密钥对”,执行“创建新的密钥对”。

5.  下载创建的CloudFront密钥对对应的私钥文件,记录下密钥对的访问键值比如“BPMAJW4W4KMUGDSHRGWD”,这些内容在后面步骤开发签名URL生成器的时候都要用到。

f45c89a82b15:cert weimen$ ls *.pem

pk-APKAJW4W4KMUGDXXXXXX.pem

说明:产生和验证CloudFront签名URL需要用到信任的AWS账号所创建的CloudFront密钥对。这个信任的AWS账号既可以是创建CloudFront发布点的IAM用户所属的AWS账号(Self),也可以是其他任何信任的AWS账号。

请注意:普通IAM账号无法创建CloudFront密钥对,必须是用根账号。

 

(二)创建S3存储桶

1.  使用具有完整S3操作权限的IAM用户登录Global AWS Web控制台

2.  访问“服务”→“存储”→“S3”,执行“创建存储桶”。

3.  在对话框中输入存储桶名称比如“cdntest0001”,选择区域,执行“创建”。

4.  记录下创建的存储桶名称,在后面步骤创建CloudFront Web发布点的时候会用到。

5.  传测试图片文件比如“earth.jpg”到新创建的S3存储桶中

6.  选中新建存储桶比如“cdntest0001”,点击“属性”标签,点开“权限”,可以看到这时候存储桶策略为空,ACL设置只允许创建者访问。

(三)上传SSL安全证书

1.  如果尚未安装AWS 命令行客户端(CLI), 请参照官方文档链接下载和安装AWS CLI: http://docs.aws.amazon.com/zh_cn/cli/latest/userguide/installing.html

2.  查找或新建一个IAM用户和对应API访问密钥(Access Key),需要保证该IAM用户拥有IAM SSL安全证书管理权限。

a)  关于如何创建IAM用户,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_users_create.html#id_users_create_console

b)  关于如何为IAM用户创建API访问密钥,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html

c)  关于如何为IAM用户设置权限策略,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies_create.html

http://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-iam-policy.html

3.  执行“aws configure”,设置IAM用户API访问密钥和默认区域名,默认区域可以为任一海外区域。

f45c89a82b15:cert weimen$ aws configure

AWS Access Key ID [****************6ZXA]: 

AWS Secret Access Key [****************NOLI]: 

Default region name [us-east-1]: 

Default output format [json]: 

4.  如果还没有CA签发的SSL安全证书,请提前完成申请,具体申请过程请参考相关CA的业务介绍说明。

5.  使用相关工具查看CA签发的安全证书内容,确认该证书包含正确域名信息。

6.  列表CA提供的证书相关文件,确认安全证书文件、私钥文件和证书链文件都存在。

f45c89a82b15:cert weimen$ ls -l

total 24

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  2065  1  4 21:54 mw.homyusc.com.crt

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  1700  1  4 21:54 mw.homyusc.com.key

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  3449  1  4 21:54 root_bundle.crt

7.  确认上面的文件内容都是X.509 PEM格式。如果不是,请使用对应工具先转化文件格式。下面的例子介绍了如何使用openssl将一个非PEM格式的.crt文件转化为PEM格式。

openssl x509 -in mycert.crt -out mycert.pem -outform PEM

8.  检查证书相关文件内容,确保格式正确

a)  安全证书文件mw.homyusc.com.crt

-----BEGIN CERTIFICATE-----

MIIFxzCCBK+gAwIBAgIQMwrcYbUzB6y7QHQiyYQuwTANBgkqhkiG9w0BAQsFADCB

hTELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu

......

SkHCiJ3TLFqNNL7D/Lou5XuUVx9OdPneDrG3qXA2KDkFFSNIbI3TJKJ0icKOJyYj

hk6nE3hxn8S8PXJ670YaPozQRhT2ZW4hF10vpzZ5PY1cMZ+TCaKyTrlY0g==

-----END CERTIFICATE-----

b)  私钥文件mw.homyusc.com.key

-----BEGIN RSA PRIVATE KEY-----

MIIEowIBAAKCAQEApeF7s/+BxjqPxri2DOhDla2XECfiJe02qG5TOLagm5e8niww

17ZmE6Ay5qR45Z8Tszkk1x3PPi0mSdkLeo24Nn9B1pwDpIIZZS3S5Pyiojz4Vu4J

......

ShsRa1MdKkWqHtWpu9HDPQwKqHhF6Z9d8MV+xGw7aieq63LfGGq0EmlMBWHRBpIQ

wV6SRCOf2YY1gHuftjmURyvNnoqntZtFfN2HHcO8QmfpRW2zpizZ

-----END RSA PRIVATE KEY-----

c)  证书链文件root_bundle.crt

-----BEGIN CERTIFICATE-----

MIIEzjCCA7agAwIBAgIQJt3SK0bJxE1aaU05gH5yrTANBgkqhkiG9w0BAQsFADB+

MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B

......

y+WutpPhI5+bP0b37o6hAFtmwx5oI4YPXXe6U635UvtwFcV16895rUl88nZirkQv

xV9RNCVBahIKX46uEMRDiTX97P8x5uweh+k6fClQRUGjFA==

-----END CERTIFICATE-----

 

-----BEGIN CERTIFICATE-----

MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw

PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG

A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow

......

QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO

TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc

eLmNzJkEN0k=

-----END CERTIFICATE-----

9.  上传SSL安全证书到AWS IAM服务

命令格式:aws iam upload-server-certificate –server-certificate-name [自定义的已上传证书名] –certificate-body [PEM格式证书文件] –private-key [PEM格式私钥文件] –certificate-chain [PEM格式证书链文件] –path [访问路径

f45c89a82b15:cert weimen$ aws iam upload-server-certificate --server-certificate-name MyTestCert

--certificate-body file://mw.homyusc.com.crt--private-key file://mw.homyusc.com.key

--certificate-chain file://root_bundle.crt --path /cloudfront/test/

{

    "ServerCertificateMetadata": {

        "ServerCertificateId": "ASCAIZCBMIGVKID653NV2",

        "ServerCertificateName": "MyTestCert",

        "Expiration": "2018-01-04T03:30:35Z",

        "Path": "/cloudfront/test/",

        "Arn": "arn:aws:iam::591809XXXXXX:server-certificate/cloudfront/test/MyTestCert",

        "UploadDate": "2017-01-15T02:13:07.848Z"

    }

}

请注意

  • 证书文件前面的“file://”不能省
  • –certificate-chain 不能省,如果没有值,就表示是用根证书。
  • –path访问路径必须是以“/cloudfront/”开头,以“/”结尾。

(四)创建CloudFront WEB发布点

1.  使用具有完整S3和CloudFront操作权限的IAM用户登录Global AWS Web控制台

2.  访问“服务”→“网络和内容分发”→“CloudFront”,执行“Create Distribution”。

3.  选择创建Web发布点

4.  请按照如下表格内容选择或输入内容:

字段名 输入值 说明
Origin Domain Name 刚刚创建的存储桶名,比如“cdntest0001” 通过下拉列表可选择
Restrict Bucket Access Yes 限制只能够通过CloudFront访问S3存储桶内容
Origin Access Identity Create a New Identity 如果您之前已经有创建的OAI,可以选择“Use an Existing Identity”,并选中该OAI,否则就让系统帮您创建一个。
Grant Read Permissions on Bucket Yes, Update Bucket Policy 自动更新S3存储桶策略, 添加CloudFront OAI用户对存储桶的读取权限。
Viewer Protocol Policy HTTPS Only 客户端只能够使用Https协议访问发布点
Alternate Domain Names 输入您的自有域名,比如“mw.homyusc.com” 该域名需要与上传的SSL安全证书中包含的域名信息一致。
SSL Certificate Custom SSL Certificate (example.com): 使用自己上传的SSL安全证书而不是默认的CloudFront安全证书。
Custom SSL Certificate (example.com): 选择之前上传到IAM服务的自有SSL安全证书
Custom SSL Client Support Only Clients that Support Server Name Indication (SNI) 部分不支持SNI的浏览器客户端将不能访问发布资源
Logging On
Bucket for Logs 选择S3存储桶 存放日志文件的S3存储桶
Log Prefix 输入CloudFront日志文件名前缀,比如“MyLog” 便于区分CloudFront日志文件和其他类型文件

5.  其余设置都保留默认值

6.  执行“Create Distribution”,记录下创建的Web发布点域名,形如“dz60cvvsxhzn8.cloudfront.net”。

7.  访问“服务”→“存储”→“S3”,查看之前创建的存储桶已经发生了权限改变:

a)  存储桶ACL增加了“awsdatafeeds”账号的读写权限,目的是实现cloudfront日志文件上传。

b)  存储桶策略增加了CloudFront OAI用户账号的只读权限,实现CloudFront访问S3存储桶内容。

8.  刚刚创建完成的Web发布点将处于“In Progress”(正在部署)状态。

9.  请耐心等待Web发布点最终变为“Deployed”(完成部署)状态。

10.  请访问您的自有域名的管理服务,创建或修改cname记录将自有域名比如“mw.homyusc.com”指向新创建的Web发布点CloudFront域名比如“dz60cvvsxhzn8.cloudfront.net”。

11.  检查自有域名的cname记录设置有效

f45c89a82b15:cert weimen$ dig mw.homyusc.com

 

; <<>> DiG 9.8.3-P1 <<>> mw.homyusc.com

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13861

;; flags: qr rd ra; QUERY: 1, ANSWER: 9, AUTHORITY: 4, ADDITIONAL: 4

 

;; QUESTION SECTION:

;mw.homyusc.com.                                             IN            A

 

;; ANSWER SECTION:

mw.homyusc.com.                              19           IN            CNAME dz60cvvsxhzn8.cloudfront.net.

dz60cvvsxhzn8.cloudfront.net. 60 IN              A             52.84.26.216

12.  在测试电脑的浏览器中输入未签名的访问URL,使用https协议和自有域名,格式形如“https://mw.homyusc.com/earth.jpg” 。

a)  浏览器就可以显示来自S3存储桶中的图片

b)  浏览器中可以查看到之前上传的SSL安全证书

说明:在这个阶段我们暂时还没有启用签名URL功能,只是设置了“自有域名”和S3存储桶“来源访问限制”功能。如果能够通过Https协议正常显示S3中的图片文件,说明前面的步骤设置正确无误。

(五)更新CloudFront WEB发布点,启用签名URL功能

1.  使用具有完整CloudFront操作权限的IAM用户登录Global AWS Web控制台

2.  访问访问“服务”→“网络和内容分发”→“CloudFront”

3.  选中之前创建的Web发布点,执行“Distribution Settings”

4.  选中“Behavior”标签,编辑“Default (*)”。

5.  设置“Restrict Viewer Access (Use Signed URLs or Signed Cookies)”为“Yes”

6.  设置“Trusted Signers”为“Self”

说明:表示使用当前登录的IAM用户所对应的AWS 账号来签名URL请求,“Trusted Signers”设置需要对应之前在创建的CloudFront密钥对时使用的AWS根账号。

13.  执行“Yes,Edit”按钮提交更新

14.  刚刚更新完成的Web发布点将处于“In Progress”(正在部署)状态。

15.  请耐心等待Web发布点最终变为“Deployed”(完成部署)状态。

(六)开发签名URL生成器

CloudFront支持使用各种开发语言和工具产生签名URL。在这篇博客里,我提供了一个使用JAVA语言开发签名URL生成器的完整例子。整个项目包括源码和依赖的库文件都打包成了完整的Eclipse项目文件,用户只需要下载后执行Eclipse的项目导入操作就可以进行代码研究和测试。

JAVA版的签名URL生成器主要依赖了一个第三方开源项目jets3t的相关库文件。jets3t项目开发了一套完整的JAVA工具来访问Amazon S3、Amazon CloudFront和 Google Storage Service。 关于jets3项目的详情请参考其官网链接。

下面的步骤详细介绍了如何使用jets3t相关工具类来开发CloudFront签名URL生成器:

1.  使用openssl转换下载的PEM格式CloudFront密钥对对应私钥文件成为DER格式

f45c89a82b15:cert weimen$ openssl pkcs8 -topk8 -nocrypt -in pk-APKAJW4W4KMUGDXXXXXX.pem -inform PEM -out cdnPK.der -outform DER

2.  下面的代码片段展示了签名URL生成器的实现细节:

a)  读取DER格式的CloudFront 密钥对的私钥文件

b)  构造被签名URL

c)  构造定制访问权限策略

d)  执行签名

e)  输出签名后的URL

public static void main(String[] args) throws Exception

{

    //1.加载Hash和签名算法类

    Security.addProvider(

    new org.bouncycastle.jce.provider.BouncyCastleProvider());

 

    // ================================================================

    // ================2.签名相关参数====================================

    // ================================================================

 

    //2.1.CloudFront为发布点分配的域名或者用户自己的域名

    String param_DistributionDomain = "自己的域名或cloudfront发布点的域名";

    //String param_DistributionDomain = "mw.homyusc.com";

 

    //2.2.转化成"*.der"格式的私钥文件

    String param_PrivateKeyFilePath = "本地保存的*.der格式的cloudfront密钥对私钥文件的带路径文件名";

    //String param_PrivateKeyFilePath = "/Users/weimen/signedurl/cert/cdnPK.der";

 

    //2.3.S3存储桶中文件的访问Key值

    String param_S3ObjectKey = "需要被访问的S3存储桶内文件访问key值";

    //String param_S3ObjectKey = "earth.jpg";

 

    //2.4.CloudFront密钥对对应的访问KEY值

    String param_KeyPairId = "使用根账号创建的CloudFront密钥对Key值";

    //String param_KeyPairId = "APKAJW4W4KMUGDXXXXXX";

 

    //2.5.待签名的URL

    //具体协议(http/https)需要和CloudFront发布点设置对应

    String param_UrlToBeSigned = "http://或者https://"

                          + param_DistributionDomain

                          + "/"

                          + param_S3ObjectKey;

 

    /*

    String param_UrlToBeSigned = "https://"

                          + param_DistributionDomain

                          + "/"

                          + param_S3ObjectKey;

    */

 

 

    //3.加载私钥文件内容

    byte[] derPrivateKey =

        ServiceUtils.readInputStreamToBytes(

            new FileInputStream(param_PrivateKeyFilePath));

 

    // ================================================================

    // ================4.定制策略相关参数================================

    // ================================================================

 

    //4.1.权限策略生效的路径,可以使用"*"和"?"来实现批量匹配,

    //具体协议(http/https)需要和CloudFront发布点设置对应

    String param_PolicyResourcePath = "http://或者https://"

                              + param_DistributionDomain

                              + "/"

                              + param_S3ObjectKey;

    /*

    String param_PolicyResourcePath = "https://"

                                + param_DistributionDomain

                                + "/"

                                + param_S3ObjectKey;

    */

 

    //4.2.签名URL失效时间   

    Date param_DateLessThan = ServiceUtils.parseIso8601Date("UTC格式的签名URL失效时间");

    //Date param_DateLessThan = ServiceUtils.parseIso8601Date("2017-06-30T22:20:00.000Z");

 

    //4.3.请求客户端的Ip地址范围CIDR设置(可选参数)    

    String param_limitToIpAddressCIDR = "CIDR格式的请求源IP地址范围";

    //String param_limitToIpAddressCIDR = "0.0.0.0/0";

 

    //4.4.签名URL生效时间(可选参数,不输入立即生效)

    Date param_DateGreaterThan = ServiceUtils.parseIso8601Date("UTC格式的签名URL生效时间");

    //Date param_DateGreaterThan = ServiceUtils.parseIso8601Date("2017-01-01T06:31:56.000Z");

 

    //5.根据输入参数创建定制策略

    String policy =

        CloudFrontService.buildPolicyForSignedUrl(

            param_PolicyResourcePath,

            param_DateLessThan,

            param_limitToIpAddressCIDR,

            param_DateGreaterThan   

    );

 

    System.out.println("[INFO]实际构造的的定制策略内容是【" + policy + "】");

 

 

    //6.执行实际签名操作(哈希+签名+Base64编码)

    String signedUrl =

    CloudFrontService.signUrl(

           param_UrlToBeSigned,

           param_KeyPairId,   

           derPrivateKey,

           policy

    );

 

    System.out.println("[INFO]输出的签名URL内容【" + signedUrl + "】");

 

}

3.  读者通过研究上面的代码和注释就可以快速理解签名URL产生的大致流程,然后根据实际需要替换代码中的“签名相关参数”和“定制策略相关参数”(蓝色字体部分),就可以快速开发出属于自己的签名URL生成器。如果需要完整的代码例子,请直接下载对应的Eclipse项目文件。

4.  例子代码产生的签名URL内容类似下面的例子:

https://mw.homyusc.com/earth.jpg?Policy=eyJTdGF0ZW1lbnQiOiBbey

JSZXNvdXJjZSI6Imh0dHBzOi8vbXcuaG9teXVzYy5jb20vZWFydGguanBnIiwiQ29uZGl0aW9uIjp7

IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNDk4ODYxMjAwfSwiSXBBZGRyZXNzIjp7IkFXU

zpTb3VyY2VJcCI6IjAuMC4wLjAvMCJ9LCJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MT

Q4MzI1MjMxNn19fV19&Signature=rJq1~uW3HZIVChPs5X5K9DnM2haH8oy488wXDAIJ6X6DBQAtVJAh

soHkPU3zaChCSGt9wG2uyuC-KslzhAw85K1b~EL52fOhuPf0uJOFAb5PUYW8R4BSyflE-

snFfzQs8laanuSmmpHNCDhGw3YrqPjFSBxm~03F5t2ElizLF~0nQdheZHLrnTrdPUMgHK6ffnANjnETul3aB4

JAzV8N1Wi5YtjjiTApiPQMJ8QrQaPScq9SonQbZdgqYuG5bzAdTxlW2gRwOfsftKSGNVK8uhczlParWZD8wa-

A5PWEaUznaBfHz1Arwiu~JnVGQTqhNPaAZs2BO95t4tqaVSrlWw__&Key-

Pair-Id=APKAJW4W4KMUGDXXXXXX

(七)验证测试

1.  当获得了经过签名的URL后,用户就可以在自己的浏览器中输入该签名URL,或者将签名URL提供给自己开发的桌面客户端或移动APP来访问S3存储桶中的对应文件。

2.  用户还可以继续测试各种异常场景:

a)  直接使用S3文件的URL访问

b)  通过CloudFront域名而不是用户自有域名访问

c)  使用Http协议而不是Https协议访问

d) 在允许的时间段之外访问

e)  使用允许的源IP地址段之外访问

基于我们之前的设置,这些操作都将返回失败消息。

总结

这篇博客完整的介绍了如何利用Amazon CloudFront签名URL功能安全地发布存放在S3存储桶中的私有内容。读者通过研究和学习签名URL生成器的源码,演练完整的CloudFront私有内容发布创建步骤,就可以快速掌握Amazon CloudFront签名URL功能的正确配置和使用方法。

 

例子源码
https://s3.cn-north-1.amazonaws.com.cn/mwpublic/projects/signedurl/SignedURL.zip

参考链接

Amazon CloudFront产品介绍

https://aws.amazon.com/cn/cloudfront/

Amazon S3产品介绍

https://aws.amazon.com/cn/s3/

创建CloudFront Web发布点

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-web.html

利用CloudFront发布私有内容

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html

在CloudFront中使用Https

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/using-https.html

利用Java语言开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CFPrivateDistJavaDevelopment.html

利用C#和.Net框架开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CreateSignatureInCSharp.html

利用PHP开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CreateURL_PHP.html

上传和管理CloudFront安全证书

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-procedures.html

签名URL定制策略

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

jets3t官网

http://www.jets3t.org/

作者介绍:

蒙维

AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,有超过十年以上电信行业和移动互联网行业复杂应用系统架构和设计经验,主要擅长分布式和高可用软件系统架构设计,移动互联网应用解决方案设计,研发机构DevOps最佳实施过程。

 

Amazon CloudFront常见错误配置及解决方法

很多的用户在最初使用CloudFront做Web类内容分发的时候遇到无法调通的情况,本文总结了用户在配置过程中遇到的常见错误,内容涵盖了大部分用户遇到的情况。

错误一  源访问权限未放开

这种错误常见于用S3做源的情况, 引起这种错误的原因是s3的访问控制没有对CloudFront开放。从浏览器中返回的错误通常类似于下图:

更具体些,可分为以下两个场景:

场景1. CloudFront使用了Restrict Bucket Access

在创建distribution的时候选择了Restrict Bucket Access 为yes, 但 Grant Read Permissions on Bucket, 选择的是”No, I Will Update Permissions”, 而用户事后却没有在s3的桶里更新policy。如下图所示。

解决方法:

方法1, 在S3中增加桶的策略,使该桶允许该CloudFront访问,以下是policy示例,其中标黄部分需要替换成用户自己的信息。

{

                "Version": "2008-10-17",

                "Id": "PolicyForCloudFrontPrivateContent",

                "Statement": [

                                {

                                                "Sid": "1",

                                                "Effect": "Allow",

                                                "Principal": {

                                                                "AWS": "arn:aws:iam::CloudFront:user/CloudFront Origin Access Identity E344H6KAFBMK0I"

                                                },

                                                "Action": "s3:GetObject",

                                                "Resource": "arn:aws:s3:::elastictcoutputthumb/*"

                                }

                ]

}

方法2, 重新创建distribution, 新建的distribution中Grant Read Permissions on Bucket选择yes, Update bucket policy, 这样当distribution创建完成后,s3桶的policy会被自动更新。

场景2. 普通的S3回源

CloudFront 并未使用Restrict Bucket Access, 这种情况下如果s3中的对象没有设置成可被公共访问,也会出现Access Denied的错误。

解决方法:

可以通过设置s3桶的bucket policy或者设置s3中对象的Object ACL来实现。 例如,通过 AWS 控制台设置存储桶的bucket policy:

通过 AWS 控制台设置S3对象的Object ACL:

注:如果想了解S3访问控制的详细内容,请参考:http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html

错误二 使用自定义域名但未在CloudFront中配置

用户有时不直接使用CloudFront的distribution产生的域名,而是使用了自定义的域名并用CNAME的方式指到CloudFront的域名, 例如使用cdn.mydomain.com  CNAME到d1cbzf61pdxxxx.CloudFront.net。此外,如果使用Route53作为DNS, 也可以不采用CNAME的方式,而是采用Alias的方式。

CloudFront规定当使用自定义域名并配置该域名使用CNAME或Alias的方式指向CloudFront distribution的域名的时候,需要在CloudFront相应的distribution中提供该自定义的域名,如果使用了多个自定义的域名,则提供多个自定义的域名。如果没有提供,就会出现类似下图的错误:

解决方法:

可以通过AWS控制台,对distribution中的Alternate Domain Names(CNAMEs)进行设置:

错误三 访问路径错误

配置完CloudFront的Behavior后,用户有时不能给出正确的url来访问想要的资源。 出现访问错误, 如果是回源s3, 返回的错误通常如下:

如果是回源的自定义网站,返回的错误根据网站的不同而不同,例如:返回”找不到相应的页面”等错误。

解决方法:

避免这种错误很简单,了解CloudFront Behavior的url与所访问的源站资源的对应方法,即可判别自己的url是否正确. 以下举例说明:

某Behavior如下,该Behavior对应的origin ID是S3-hxybucket/Picture:

进入到Origin查看,可知Origin Domain Name and Path是hxybucket.s3.amazonaws.com/Picture

如果通过d1cbzf61pdxxxx.CloudFront.net/dog.jpg访问的话, 对应的源站资源是hxybucket.s3.amazonaws.com/Picture/dog.jpg

如果通过d1cbzf61pdxxxx.CloudFront.net/jpg/dog.jpg访问的话,对应的源站资源是hxybucket.s3.amazonaws.com/Picture/jpg/dog.jpg

即: 将CloudFront域名后面的路径追加到Origin Domain Name and Path (注意,除了Domain Name之外,还有Path) 所对应的路径后面, 就是对应到源站的资源, 用户通过该路径即可判断所使用的url是否正确。

错误四 HTTP Method 设置不当

在创建Behavior的时候, allowed http methods选项的默认值是GET和HEAD, 有时用户会使用其他的HTTP method, 例如POST, 此时如果还是用默认值,就会出错,返回的错误通常如下:

“This distribution is not configured to allow the HTTP request method that was used for this request. The distribution supports only cachable requests.”

解决办法:

办法很简单,在Behavior中重新设定一下Allowed HTTP Methods选项,使其包含所用的HTTP Method.

错误五 设置了Restrict Viewer Access 却没有使用Signed URL或Signed Cookie

在创建Behavior的时候,Restrict Viewer Access (Use Signed URLs or
Signed Cookies)选项的默认值是No, 如果用户改成了Yes, 此时该Behavior对应的资源必须使用Signed URL 或者Signed Cookie的方式访问,如果使用普通的Url访问,返回的错误通常如下:

解决方法:

方法1.使用signed url 或signed Cookie进行访问,具体参考:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html

方法2. 将Restrict Viewer Access (Use Signed URLs or
Signed Cookies)的值改为No。如图:

错误六  Object Caching 设置不当

虽然能够访问到源,但有时用户会反映使用了CloudFront并没有加速访问,有时甚至效果还不如未使用CloudFront时。 这很可能是由于Object Caching设置不当造成的。

解决方法:

Object Caching有两个选项,分别是Use Origin Cache Headers 和 Customize。默认选项是前者。但是,当默认选择了Use Origin Cache Headers,而源的HTTP header中却没有Cache-control的头,那返回内容就不被缓存了。 因此,用户需谨慎选择,当源的返回值中没有Cache-control头的情况下,选择Customize,Customize中的Default值将会成为TTL时间(时间单位是秒)。

另外,如果源的返回值中存在Cache-control,而Object Caching又选择了Customize, 这种情况下返回的内容肯定会在CloudFront边缘节点中被缓存。但CloudFront会使用哪个值作为TTL呢? 这个在CloudFront 文档中有详细的描述, 详见: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html

作者介绍:

韩小勇

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,实施和推广,在加入AWS之前,从事电信核心网系统上云的方案设计及标准化推广 。