亚马逊AWS官方博客
Amazon CloudFront 用户域名部署及典型故障排查
Amazon CloudFront 用户域名部署及典型故障排查
Amazon CloudFront是亚马逊云科技的CDN(内容分发网络)服务,在全球拥有超过300个边缘站点并通过亚马逊云科技骨干网与亚马逊云科技区域(Region)互联。借助此全球边缘网络,CloudFront可将您的Web内容以低延迟和高可用性分发至世界各地。除了CDN加速效果外,在安全性上,CloudFront支持用户自定义域名,并关联该域名的SSL证书,使用HTTPS方式进行内容分发。
本文将为您介绍CloudFront用户自定义域名创建及SSL/TLS证书关联和生命周期管理,即通过Amazon Certificate Manager(ACM)进行自动的证书申请/证书更新/证书吊销。此外,不少用户在配置了CloudFront HTTPS源站后,会产生HTTP 502(源站证书验证失败)的报错,本文将为您解释该问题产生的原因和修复的方法。
Amazon CloudFront的HTTPS支持
CloudFront支持端到端的加密通讯,包括查看器(客户端)与CloudFront边缘站点之间使用HTTPS,以及CloudFront边缘站点与您的源站之间使用HTTPS。
从CloudFront边缘站点到源站间的HTTPS
源设置中,在使用ALB/EC2/自定义源作为源站时,将配置从CloudFront边缘站点回源时的协议。
如果希望使用HTTPS回源,可以选择:
- 仅HTTPS
- 匹配查看器(当且仅当查看器协议策略为HTTPS only或HTTP重定向至HTTPS时)
最低源SSL协议保持默认设置即可。
从查看器到CloudFront边缘站点的HTTPS
在行为设置中,将配置从查看器(客户端)到CloudFront边缘站点的协议策略。
如果希望使用HTTPS访问分配,则可以选择:
- HTTPS only 或
- 重定向HTTP至HTTPS
CloudFront分配在创建完成后会提供一个形如d123abcxxx.cloudfront.net的分配地址用于访问加速,此时会使用CloudFront提供的默认SSL证书。通常用户会希望使用自己的域名来进行访问,在分配设置中,可以通过添加备用域名(CNAME)并关联SSL证书来实现。
为Amazon CloudFront分配设置备用域名(CNAME)并关联SSL证书
在分配设置中填写好备用域名后,为了验证域名,以及实现查看器(客户端)到CloudFront分配的HTTPS连接,需要为备用域名关联SSL证书。CloudFront结合亚马逊云科技 Certificate Manager(ACM)提供了以下3种方法用于申请或上传证书。
*提示:即使查看器(客户端)到CloudFront边缘站点使用HTTP,如果您自定义域名,CloudFront也会要求您关联SSL/TLS证书,以确保自定义域名的合法性和唯一性(SSL/TLS证书的申请过程包含了对您的域名的验证)。
在ACM中申请免费公有证书
亚马逊云科技 Certificate Manager(ACM)服务能够简化创建、存储和续订公有 SSL/TLS X.509 证书和密钥的复杂操作,提供免费的公有SSL证书,且证书受大多数浏览器、操作系统和移动设备的信任,并可以与Elastic Load Balancing,Amazon CloudFront, Amazon API Gateway等亚马逊云科技服务集成。如果您的域名尚未拥有公有证书,可以从ACM中免费申请。
在CloudFront分配设置中填写好分配的备用域名后,点击下方的请求证书按钮将自动跳转至ACM服务控制台,或者您也可以在亚马逊云科技管理控制台中搜索ACM服务进入。请注意为了使申请的证书能够与CloudFront分配关联,务必确认右上角的区域为美国东部弗吉尼亚北部(us-east-1)区域。
第一步:添加域名
在添加域名时,可以使用通配符来匹配多个子域名,这样对于同一个顶级下的多个二级域名能够共用同一个ACM公有证书,而不必多次申请。在这个例子中,我将使用*.example.com来保护www.example.com。
需要注意的是,*.example.com无法保护三级域名如test.login.example.com或一级域名example.com。如果需要保护其他域名,可以点击“为此证书添加另一个名称”继续添加其他域名。
现在我们选择默认的DNS验证方法,点击请求。
* DNS验证方法是用域名记录修改的方式,帮助证书颁发机构确认证书申请人能够在example.com下增加颁发机构指定的DNS记录内容。从而证明证书申请人对example.com域名的拥有权。
第二步:对域名进行DNS验证
在ACM控制台,可以看到刚刚申请的证书处在“等待验证”状态。进入该证书的详情,复制CNAME名称和CNAME值,并在您的DNS服务中创建一条CNAME记录。如果您使用的是Amazon Route53托管域名,则可以点击“在Route 53中创建记录”一键完成记录创建。
在Route53中创建的CNAME记录如下图所示。
第三步:将证书在CloudFront分配中关联
确认在DNS服务中创建正确的CNAME记录后,刷新ACM控制台即可发现证书已成功颁发。
回到CloudFront分配设置,点击自定义SSL证书右侧的刷新按钮,在下拉菜单中将显示刚刚在ACM中申请的公有证书。
在安全策略上,建议使用推荐的策略以实现最广泛的浏览器兼容性。
在ACM中上传已有的第三方SSL证书
如果您的域名已经在第三方证书颁发机构(CA)申请过SSL证书,亦可以上传至ACM中来和CloudFront分配关联。在上传证书时,同样需要确认ACM服务在美国东部弗吉尼亚北部(us-east-1)区域。
对于可导入至ACM的SSL/TLS证书具有以下要求,详见
进入ACM导入证书页面,在步骤1输入证书详细信息,有三个部分需要填写,分别是证书正文 certificate body、证书私钥 private key、证书链 certificate chain。而大多数从第三方购买的SSL证书,通常只包含两个文件如xxx.pem和xxx.key,导入ACM时请参考以下方式填写:
- 打开xxx.key文件,复制完整内容至证书私钥处,以 —–BEGIN PRIVATE KEY—– 开头并以 —–END PRIVATE KEY—– 结尾。
- 打开xxx.pem文件,文件中包含两段以—–BEGIN CERTIFICATE—– 开头并以 —–END CERTIFICATE—–结尾的内容。分别复制第一段至证书正文,第二段至证书链处。
在步骤3审核并导入,可以看到刚刚导入的证书的详情,证书关联的域、过期时间、加密算法会正确显示。
将第三方SSL证书导入至ACM后,您同样可以在CloudFront分配设置的自定义SSL证书下拉框中看到刚刚上传的证书。
在IAM中上传已有的公有证书
如果您使用的是亚马逊云科技中国区,由于CloudFront关联自定义SSL证书时仅支持从IAM中选择,可以通过以下方式将第三方SSL证书上传至IAM。
在CloudFront分配设置页面,点击上载证书至IAM。
证书的内容按以下形式填写:
- 私有密钥:复制xxx.key的完整内容,以 —–BEGIN PRIVATE KEY—– 开头并以 —–END PRIVATE KEY—– 结尾。
- 证书正文:复制xxx.pem的第一段,以“—–BEGIN CERTIFICATE—– 开头并以 —–END CERTIFICATE—–“结尾。
- 证书链:复制xxx.pem的第二段,以“—–BEGIN CERTIFICATE—– 开头并以 —–END CERTIFICATE—–“结尾。
最后,在DNS服务中,为您设置的备用域名创建一条CNAME记录,指向CloudFront分配地址,即可实现通过备用域名访问。如果您使用的是Route 53中,可以使用别名记录将流量路由至CloudFront分配。
修复使用ALB作为源站时的HTTP 502错误
至此,我们已基本完成端到端的CloudFront HTTPS配置。如果您使用网络负载均衡器ALB作为源站,访问备用域名发生HTTP 502报错时,可参考以下原理和方法进行正确配置。
业务拓扑
请求流:客户端—HTTPS—login.test.example.com (CloudFront Distribution: d123abc.cloudfront.net) —HTTPS回源— Origin (ALB: LOGINTEST-abc-12345.us-east-1.elb.amazon亚马逊云科技.com) —HTTP— EC2。按照此请求流,客户端看到HTTP 502报错。
故障分析
- CloudFront分配E1234DEFGH上配置的证书为ACM颁发的*.test.example.com通配符证书。
- 源站ALB上安装为ACM颁发*.test.example.com证书。
- 通过login.test.example.com的请求里,客户终端使用的是login.test.example.com作为HTTPS Host请求头来访问login.test.example.com。
- 客户终端侧的Host请求头 login.test.example.com,在默认CloudFront Cache Request Policy里,会在回源时由CloudFront Distribution point改写为源站Host: LOGINTEST-abc-12345.us-east-1.elb.amazonaws.com(注意CloudFront回源时的Host请求头默认都会由客户终端侧的Host请求头改写为和回源uri一致。)
- 由于Host请求头LOGINTEST-abc-12345.us-east-1.elb.amazonaws.com与ALB证书*.test.example.com没有匹配,因此CloudFront distribution point在获取源站内容时,SSL匹配报错导致HTTPS无法完成。
最终发生502报错。
修复方案
方案1:在CloudFront行为设置中转发Host请求头
- 在源站ALB上安装与客户终端侧提交的Host请求头login.test.example.com匹配的*.test.example.com的证书。
- 在CloudFront Behavior里的Origin request policy里选择“AllViewer” policy,强制CloudFront distribution point在获取源站内容时,保留客户终端侧的Host请求头.
此时从CloudFront边缘站点回源,Host请求头将使用login.test.example.com,可以匹配ALB上的证书*.test.example.com,SSL匹配要求得以满足,HTTPS回源过程顺利完成,502报错消失。
CloudFront行为配置截图如下:
方案2:替换源站地址为ALB的CNAME地址
- 在源站ALB上安装通配符证书*.test.example.com的证书
- 在DNS服务中,创建一条CNAME记录,该记录的主机名能被*.test.example.com证书保护,如origin.test.example.com,指向ALB的DNS地址(LOGINTEST-abc-12345.us-east-1.elb.amazonaws.com)
- 将CloudFront的源站地址改为ALB的CNAME地址(origin.test.example.com)
此方案不需要修改CloudFront分配的request policy,因为此时从CloudFront边缘站点回源,Host请求头将由CloudFront改写为源站地址origin.test.example.com(而非ALB默认的DNS地址),该Host可以匹配ALB上的证书*.test.example.com,SSL匹配要求得以满足,HTTPS回源过程顺利完成,502报错消失。
方案小结
在调试HTTPS回源的CloudFront案例中,502错误经常会是证书相关的回源错误。
原因:CloudFront回源时,默认不会保持每一个view的HTTP请求头。尤其是Host请求头会被改动成为源站对应的域名。本例中Request Policy选择了托管策略AllViewer来转发所有的HTTP header、Query string、Cookie,当然您也可以创建自己的策略来选择在从CloudFront边缘站点回源时需要转发的参数。
引申:访问CloudFront分配默认地址时出现403报错
在我们按照方案1或方案2后进行修复后,现在直接用HTTPS访问CloudFront分配默认地址(如d123abc.cloudfront.net)报错代码403,具体现象如下:
原因:请求回源时的Host请求头为d123abc.cloudfront.net,而源站只接收Host为*.test.example.com的请求头,因此源站不予服务。
总结
本文介绍了CloudFront HTTPS的基本设置,以及在使用备用域名时如何关联域名并申请或上传SSL证书的详细步骤。同时,介绍了在使用ALB作为源站时,由于证书配置错误导致的回源失败,如何修复该HTTP 502报错场景的原理和方案。这个过程同样可以供在EC2或其他自定义源站上安装第三方SSL证书时遇到502报错作为排错参考。
参考文档
[2] 使用备用域名和 HTTPS
[3] 控制源请求
[4] SSL/TLS证书申请及使用方法
[5] HTTP 502 状态代码 (Bad Gateway)