Category: 网络和内容发布


新增 – 通过 IP 地址在 AWS 和本地资源间实现应用程序负载均衡

作者:Jeff Barr / 原文链接

去年,我介绍了有关新型 AWS 应用程序负载均衡器的信息,并展示了如何针对 EC2 实例以及在容器中运行的微服务,用它进行第 7 层 (应用程序) 路由。

在向 AWS 迁移的这个漫长过程中,有些客户会构建混合应用程序。这些客户告诉我们,他们希望使用单个应用程序负载均衡器,在现有本地资源以及 AWS 云中运行的新资源组合中分配流量。其他客户则希望将流量分配到分散在两个或多个 Virtual Private Cloud (VPC) 中的 Web 或数据库服务器中,在同一实例上托管 IP 地址不同但端口号相同的多项服务,并为不支持服务器名称指示 (SNI) 的客户端提供基于 IP 的虚拟托管支持。还有一些客户则希望在同一实例上 (或许是在容器内) 托管某项服务的多个实例,同时使用多个界面和安全组来实施精细访问控制。

这些情况会出现在各种混合、迁移、灾难恢复和本地使用情形及场景中。

路由到 IP 地址
应用程序负载均衡器现在可以将流量直接路由到 IP 地址,以满足这些使用情形。这些地址可以与 ALB 位于同一 VPC 中、位于同一区域中的对等 VPC 中、位于与 VPC 连接的 EC2 实例上 (通过 ClassicLink),或者位于 VPN 连接或 AWS Direct Connect 连接另一端的本地资源上。

应用程序负载均衡器已将目标分成了目标组。在今天发布的版本中,每个目标组现在都有一个目标类型属性:

instance – 和以前一样,目标通过 EC2 实例 ID 进行注册。

ip – 将目标注册为 IP 地址。您可以对负载均衡器 VPC 内的目标使用来自负载均衡器 VPC CIDR 的任何 IPv4 地址,对负载均衡器 VPC 之外的目标 (包括对等 VPC、EC2-Classic,和可通过 Direct Connect 或 VPN 访问的本地目标) 使用 RFC 1918 范围 (10.0.0.0/8、172.16.0.0/12 和 192.168.0.0/16) 或 RFC 6598 范围 (100.64.0.0/10) 内的任何 IPv4 地址。

每个目标组都有负载均衡器和运行状况检查配置,并一如既往地将指标发布到 CloudWatch。

假设您正处于将应用程序迁移到 AWS 的过渡阶段,或者希望使用 AWS 通过 EC2 实例来扩充本地资源,并需要将应用程序流量分配到 AWS 和本地资源中,则可以将所有资源 (AWS 和本地) 注册到同一个目标组并将该目标组与负载均衡器相关联。或者,您也可以使用两个负载均衡器在 AWS 和本地资源中实现基于 DNS 的加权负载均衡,即一个负载均衡器用于 AWS,另一个负载均衡器用于本地资源。如果应用程序 A 的后端位于 VPC 中,而应用程序 B 的后端位于本地,在这种情况下您就可以将每个应用程序的后端放在不同的目标组中,并使用基于内容的路由将流量路由到每个目标组。

创建目标组
接下来,我将介绍如何在创建应用程序负载均衡器的过程中创建目标组,从而将流量发送到一些 IP 地址。输入一个名称 (ip-target-1),并将 ip 选为目标类型:

然后输入 IP 地址目标。此类地址可以来自托管负载均衡器的 VPC:

也可以是上述某个私有范围 (适用于位于托管负载均衡器的 VPC 之外的目标) 内的其他私有 IP 地址:

检查设置并创建负载均衡器之后,只要指定的 IP 地址通过运行状况检查,系统便会向其发送流量。每个负载均衡器最多可以包含 1000 个目标。

我可以随时检查目标组并编辑目标集:

如您所见,在我抓取这个屏幕截图时其中一个目标的运行状况不佳 (这是故意设计的)。每个目标组的指标都会发布到 CloudWatch;我可以在控制台中查看这些指标,还可以创建 CloudWatch 警报:

现已推出
此功能现已在所有 AWS 区域推出,您可以立即开始使用。

Jeff

在AWS上部署SAP HANA – 您的选项是什么?

作者:Sabari Radhakrishnan, Amazon Web Services(AWS)的合作伙伴解决方案架构师

译者:戴俊, Amazon Web Services(AWS)的专业服务团队SAP顾问 | 原文链接

您是否计划将SAP应用程序迁移到SAP HANA平台或使用SAP HANA启动新的实施? 如果是这样,您可能会想知道Amazon Web Services(AWS)提供什么选项来运行SAP HANA工作负载。 在这篇博文中,我想讨论SAP HANA所需的核心基础架构组件以及AWS提供的构建模块,以帮助您构建AWS上的SAP HANA虚拟设备。 我希望这些信息可以帮助您了解概念层面的部署选项。 这是我们将在AWS主题上发布各种SAP的一系列博文中的第一篇,因此请经常回来看看。

如果您遵循SAP HANA定制数据中心集成(TDI)模式,内存,计算,存储和网络是SAP HANA所需的四个关键基础架构组件。 其中,内存是唯一取决于您的数据大小的变量。 计算,存储和网络的要求是从内存大小预设或派生的。 例如,根据内存大小,SAP已经有了标准的CPU核数到内存比的要求,以确定您需要进行计算的CPU核心数量。 关于存储,无论内存大小如何,您需要能够满足SAP HANA硬件配置检查工具(HWCCT)指南中规定的不同块大小和其他KPI的特定吞吐量要求。 最后,对于网络,特别是对于横向扩展情况,不论内存大小,您都需要能够在SAP HANA节点之间至少支持9.5 Gbps的网络吞吐量。

在过去的几年中,AWS与SAP紧密合作,以验证在AWS平台上运行SAP HANA工作负载的计算和存储配置。 我们如何实现这个目标的呢? 答案是,AWS已经设计了具有不同内存大小的Amazon Elastic Compute Cloud(Amazon EC2)实例,以满足SAP对SAP HANA的所有严格的性能要求,包括适用于计算的CPU核心到内存比例。 此外,Amazon Elastic Block Store(Amazon EBS)在许多情况下满足了TDI模型的存储KPI。 最后,EC2实例的网络带宽满足或超过了横向扩展模式下节点间通信的9.5 Gbps要求。

我们来仔细看看这些构建模块和配置选项。

内存和计算

AWS提供了几种EC2实例类型来支持不同类型的工作负载。有两个EC2实例系列非常适合SAP HANA工作负载:内存优化的R3和R4实例以及高内存X1实例。这些实例系列是针对内存中的工作负载(如SAP HANA)专门制定的。这些实例系列及其包含的实例类型为您提供了运行SAP HANA工作负载的各种计算选项。对于在线分析处理(OLAP)工作负载(例如,HANA上的SAP Business Warehouse,SAP BW / 4HANA,数据集市等),您可以垂直扩展,从244 GiB到2 TB,水平扩展一直到14 TB,并被SAP完全支持。还要注意,我们已经在AWS实验室中成功测试了多达25个节点的部署或总共50 TB的RAM。对于在线交易处理(OLTP)工作负载(例如,HANA上的SAP Business Suite,SAP S4 / HANA,SAP CRM等),您现在可以从244 GiB垂直扩展到2 TB。随着AWS继续推出具有最新CPU代数的新实例类型,我们将与SAP密切合作,为SAP HANA工作负载的这些实例类型进行认证。通过SAP认证和支持的SAP HANA硬件目录中的“认证IaaS平台”页面,查看可用于SAP HANA工作负载的生产中的所有经过认证的AWS实例类型。在非生产工作负载的给定实例系列中,您可以随时使用较小的实例大小,例如r3.2xlarge,r4.2xlarge等,以降低总体拥有成本(TCO)。请记住,这些是云原生实例,使您可以灵活地将SAP HANA系统的内存空间从64GB无缝更改为2 TB,反之亦然,几分钟内即可实现SAP HANA实施的前所未有的灵活性。

以下图表总结了我刚刚描述的内存和计算选项。

注 – 对于SAP Business One,所适用的SAP HANA的版本,以及可以使用其他实例和内存大小。 请参考关于这个话题的另一个博文。

存储

对于SAP HANA的持久性块存储,AWS提供多种选项。对于您的性能敏感数据和日志卷,以及针对SAP HANA备份的成本优化/高吞吐量磁性EBS卷(st1),我们有两种支持SSD的EBS卷类型(gp2和io1)。

  • 使用通用SSD(gp2)卷类型,您可以驱动高达每卷160 MB / s的吞吐量。为了实现TDI模型所需的最大吞吐量为400 MB / s,您必须为SAP HANA数据和日志文件分配三个卷。
  • 配置的IOPS SSD(io1)卷提供每卷最多320 MB / s的吞吐量,因此您需要至少分两个卷来实现所需的吞吐量。
  • 通过吞吐量优化的硬盘(st1)卷,您可以通过大尺寸块的顺序读写实现高达500 MB / s的吞吐量,这使st1成为存储SAP HANA备份的理想选择。

一个关键点是每个EBS卷都会在其AWS可用区域内自动复制,以保护您免受故障,提供高可用性和耐久性。因此,您可以在操作系统级别配置RAID 0阵列,以获得最佳性能,而不必担心您的卷的额外保护(RAID 10或RAID 5)。

网络

网络性能是SAP HANA的另一个关键因素,尤其是横向扩展系统。 每个EC2实例提供一定量的网络带宽,而像X1这样的一些最新实例系列可为您的SAP HANA需求提供高达20 Gbps的网络带宽。 此外,许多实例为Amazon EBS存储后端提供专用网络带宽。 例如,最大的X1实例(x1.32xlarge)提供20 Gbps的网络带宽和10 Gbps的专用存储带宽。 R4(r4.16xlarge)除了专用的12 Gbps存储带宽外还提供20 Gbps的网络带宽。 以下简要介绍了SAP认证实例的网络功能。

*网络和存储流量共享相同的10 Gbps网络接口

操作系统(OS)

SAP支持在SUSE Linux Enterprise Server(SLES)或Red Hat Enterprise Linux(RHEL)上运行SAP HANA。 AWS都支持这两种操作系统版本。 此外,您可以在AWS Marketplace中使用SAP HANA特定的SUSE和Red Hat映像来快速开始。 您还可以选择携带自己的操作系统许可证。 请在未来的博文中,查看有关SAP HANA在AWS上的操作系统选项的详细信息。

把以上内容搭建起来

您可能会问:“AWS提供与TDI类似的SAP HANA的这些构建模块非常好,但是如何将这些组件放在一起构建一个满足SAP对AWS要求的系统?”AWS客户几年前就问了这个问题,这就是为什么我们构建了AWS SAP HANA快速启动。此快速启动使用AWS CloudFormation模板(基础架构作为代码infrastructure as code)和自定义脚本来帮助配置AWS基础架构组件,包括存储和网络。快速启动有助于设置SAP HANA安装的操作系统先决条件,并且可以在携带自己的软件和许可证时安装SAP HANA软件。快速启动是可以在全球许多AWS地区使用的自助服务工具。在不到一小时的时间内,它们可以以一致,可预测和可重复的方式为您的SAP HANA系统提供基础设施,无论是单节点还是横向扩展系统。查看在SAP RE:Invent 2016会议期间与SAP联合提交的SAP HANA Quick Start的演示文稿

我们强烈建议您使用AWS快速启动为您的SAP HANA部署配置基础架构。 但是,如果无法使用快速启动(例如,因为要使用自己的操作系统映像),则可以手动配置SAP HANA环境,并将构建模块放在一起。 只需确保遵循快速入门指南中有关存储和实例类型的建议。 为了具体目的,我们还在“ SAP HANA on AWS 手动部署指南”中的SAP HANA中提供了分步说明。 (手动部署指南很快将会更新,以包括最新操作系统版本的说明,包括RHEL。)

备份和恢复

以可靠的方式备份和恢复SAP HANA数据库的能力对于保护业务数据至关重要。 您可以使用本机SAP HANA工具将数据库备份到EBS卷,并最终将备份的文件移动到Amazon Simple Storage Service(Amazon S3),以提高其耐用性。 Amazon S3是高度可扩展和耐用的对象存储服务。 Amazon S3中的对象可以冗余地存储在一个区域内的多个设施中,并提供11个9的耐久性。 您还可以选择使用与Amazon S3集成的企业级备份解决方案,如Commvault,EMC NetWorker,Veritas NetBackup和IBM Spectrum Protect(Tivoli Storage Manager)以及SAP HANA Backint界面。 这些合作伙伴解决方案可以帮助您将SAP HANA数据库直接备份到Amazon S3,并使用企业级软件管理备份和恢复。

高可用性(HA)和灾难恢复(DR)
HA和DR是在SAP HANA上运行的关键业务应用程序的关键。 AWS提供了几个构建模块,包括全球各个AWS区域和每个AWS区域内的多个可用区域,您可以根据RTO和RPO的要求设置HA和DR解决方案。 无论您是寻求基于成本优化的解决方案还是基于停机时间优化的解决方案,SAP HANA HA / DR架构都有一些独特的选择,请查看SAP HANA HA/DR 指南,以了解有关这些更多信息。 在未来的博文中,我们将深入探讨这一主题。

系统迁移

在实际迁移的时候,您可以使用SAP Software Provisioning Manager(SWPM)和Software Update Manager(SUM)的Database Migration Option(DMO)等标准SAP工具集,或第三方迁移工具来把在任何数据库上运行的SAP应用程序迁移到AWS上的SAP HANA。 SAP到AWS迁移过程与典型的本地迁移方案没有太大的不同。 在本地场景中,您通常将源和目标系统驻留在同一数据中心。 当您迁移到AWS时,唯一的区别是您的目标系统驻留在AWS上,因此您可以将AWS视为自己的数据中心的扩展。 还有一些选项可用于在迁移过程中将导出的数据从本地数据中心传输到AWS。 我建议您查看 Migrating SAP HANA Systems to X1 Instances on AWS,以更好地了解您的选项。

其他注意事项包括操作,调整大小,缩放,与其他AWS服务(如Amazon CloudWatch)的集成,以及大数据解决方案。 我们将在未来的博文中详细讨论这些。 同时,我们也鼓励您使用AWS SAP HANA快速入门来在AWS上使用SAP HANA。 要了解有关在AWS上运行SAP工作负载的更多信息,请参阅AWS网站上列出的白皮书

最后,如果您需要一个超出了目前可用规模的可扩展系统,请与我们联系。 我们很乐意与您讨论您的要求,并与您一起实施。

– Sabari

 

译者

戴俊,AWS中国专业服务团队SAP咨询顾问,在加入AWS之前,曾供职于SAP和EMC历任SAP技术顾问及SAP解决方案工程师,在SAP系统架构设计与迁移方面有着丰富的经验。现任职于AWS中国专业服务团队,主要为客户提供云上SAP系统架构设计,SAP上云迁移等咨询服务。

使用AWS Application Load Balancer实现基于主机名的路由分发

负载均衡器在应用架构设计中是重要的组件,负责接收来自客户端的流量,将流量按一定的算法转发给后端的一组实例,并将后端实例的响应再返回给客户端。AWS提供一款托管的负载均衡服务, Elastic Load Balancer(简称ELB),ELB除了能够做负载均衡分发流量之外,还能对后端的实例健康检查,并将流量仅转发给通过健康检查的实例,同时ELB还能与自动扩展组(Auto Scaling Group)以及监控服务(CloudWatch)配合,设置根据后端实例CPU使用率的高低,流量大小,处理时间长短等指标,自动完成添加或缩减实例数量。

ELB又分两种,Classic ELB和Application Load Balancer(简称ALB),ELB的一个重要组件是侦听器,前者支持4层和7层的协议和端口(TCP,SSL,HTTP,HTTPS),对后端实例按轮询(TCP协议)或者最少未完成请求数(HTTP协议)的算法对后端实例进行流量转发。

ALB是应用层负载均衡器,支持HTTP/HTTPS的协议,与Classic ELB不同的是,ALB支持基于请求路径的分发,即根据HTTP标头的请求URL路径的不同,分发给后端不同的目标组(Target Group)。目标组是一个或多个目标(这里的“目标”可以是EC2实例)的集合,通常一组目标运行相同的应用或服务,一个目标可以注册到一个或多个目标组中。在目标组中可以配置运行状况检查,实例监控,等待连接耗尽及粘性会话等等。ALB中的规则决定了如何将流量路由到后端不同的目标组,每条规则对应一个目标组、条件及优先级,一旦匹配规则,则执行相应的流量路由,比如将请求URL中路径是/api的请求路由给运行api服务的目标组,将请求URL中路径是/mobile的访问路由给mobile的目标组。

两者的转发模型可见下图。

过去ALB仅支持基于请求路径的流量分发,客户为了实现基于主机名的分发往往使用多组Classic ELB或Classic ELB + Nginx集群的方式,现在ALB提供了新功能,即可以基于主机名进行路由分发,详情请参考:

https://aws.amazon.com/cn/elasticloadbalancing/applicationloadbalancer/

接下来,我们将详细介绍如何使用ALB完成基于主机名的流量分发。

本例中我们将创建以下资源:

(1)1个ALB;

(2)5个目标组,分别为api-prod,api-sandbox,mobile-prod,mobile-sandbox,default;

(3)每个目标组注册不同的EC2实例,其中api-prod目标组将注册两个EC2实例;

(4)一个侦听器;

(5)创建基于主机名和路径的分发规则,实现流量的分发。

1、创建目标组

2、输入目标组名称,选择协议(HTTP/HTTPS)及端口,ALB所在的VPC,配置运行状况检查(协议,路径,阈值等)。此处我们选择了默认HTTP,路径/。

3、注册实例

目标组的重要实体是目标(比如说EC2实例),在此将实例注册到目标组下面,注意选中实例后点击”添加到已注册”,然后保存。此处我们选中了该目标组对应的实例ALBDemo_api_prod,ALBDemo_api_prod_2两个实例。您可以向一个或多个目标组注册多个目标实例以便满足需求。只要注册过程完成且新注册的目标实例通过初始运行状况检查,负载均衡器就会开始将请求路由至此目标。同样,您也可以从目标组取消目标注册。

同理创建api-sandbox,mobile-prod,mobile-sandbox,default目标组,此处省略创建过程。

创建完成后,选中目标组,在目标页我们可以看见注册到该目标组的实例的状态,healthy表示实例正常,另外该状态还有unhealthy(实例未通过健康检查),initial(实例注册中),unused(无流量传入,该目标组未注册到ALB)等。

4、创建负载均衡器

下面我们来创建ALB

5、选择ELB类型

这里我们选择应用程序负载均衡器ALB

6、配置负载均衡器

输入ALB名称,模式可选择该ALB面向Internet或是内部使用;配置侦听器协议,端口,根据需要可以配置多个侦听器,此处我们选择HTTP/80;同时选择ALB部署在哪个可用区及子网,建议多可用区方式部署,同样将应用部署在多可用区,达到高可用的设计目标。

7、配置安全设置

如果侦听器配置了HTTPS,需要配置证书。使用HTTPS,ELB可以完成与客户端的SSL安全连接的建立与SSL卸载,减轻后端服务器的压力。

如果从ACM(AWS Certificate Manager)申请过证书,则可以直接选择该证书,也可以自己上传证书到IAM或者在此上传证书。由于此次我们仅配置了HTTP 80端口侦听器,此处将不配置证书。配置安全证书的截图如下:

8、配置安全组

安全组的概念及用法此处不做复述,我们可以为ALB配置安全组,仅允许指定的协议、端口及来源的流量进入ALB

9、配置路由

这里可以选择”现有目标组”,选择我们前面的创建的default目标组。此处只能选择一个目标组,我们可以在创建完成后,对此ALB添加编辑规则的时候对应路由规则添加目标组。

10、注册目标

11、审核

创建完成后,可以在负载均衡器的控制台看到该ALB的相关描述与信息。

12、配置规则

选中该ALB,在页面下方的侦听器下按端口选择“查看/编辑规则”。

13、添加/编辑规则

与之前不同的是,现在ALB提供了一个规则编辑器。进入规则编辑器后,我们看到的是一条默认规则,并看到目标组是我们前面创建过程中选择的default组。点击左上方”+”,可以添加规则。

目前路由规则支持三种方式:

a.基于URL路径;

b.基于主机名(New Feature);

c.基于主机名+路径(New Feature);

点击&,可以实现基于主机名+路径的规则;

添加了4条规则,将不同主机及路径的流量分发到不同的目标组,如下:

规则 规则(if) 目标组(then)
1 路径/sandbox/* &主机名为api.shishuai.tech api-sandbox
2 主机名为api.shishuai.tech api-prod
3 路径/sandbox/* &主机名为mobile.shishuai.tech mobile-sandbox
4 主机名为mobile.shishuai.tech mobile-prod

通过左上角的添加、编辑、排序、删除可以对规则进行相应的修改与排序,需要注意的是,流量路由匹配规则的时候按规则的顺序匹配,并按最先匹配到的规则执行相应的路由。最多可以添加75条规则。每条规则在主机名处支持最多3个通配符(”*”或者”?”)。

最后规则配置完成,我们检查下规则是否生效。使用Route53 DNS解析服务,将相应的域名(本例中为api.shishuai.tech和mobile.shishuai.tech)CNAME到该ALB的域名(本例中为ALBDemo-2043343612.us-west-2.elb.amazonaws.com,可在选中该ALB,在描述页中看到该DNS地址)。

本例中每个EC2有一个简单的页面,表明自己主机名,以及instance-id,以此区分是否按规则路由到相应的EC2。

http://api.shishuai.tech

在api-prod目标组,我们注册了两台机器,刷新几次会出现另一台EC2的页面。

http://api.shishuai.tech/sandbox/

http://mobile.shishuai.tech

http://mobile.shishuai.tech/sandbox/

综上所述,使用应用负载均衡器基于主机名/路径的流量分发特性,客户可以仅用一组应用负载均衡器就可实现将流量路由给多个后端服务,这可以大大简化客户的架构、减轻运维负担以及优化成本。

作者介绍

王世帅

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内教育、医疗行业的应用和推广。在加入AWS之前曾在国航担任系统工程师,负责存储方案的架构设计,在企业私有云方面有丰富经验。

 

使用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最佳实施过程。

 

如何在AWS上构建基于 OpenSwan 的软件 VPN 解决方案

概述

随着云的普及以及即用即付的模式,正在被大家逐渐接受,那么在初期从原始数据中心到云迁移的过程中,为了保证数据的平稳迁移,并不推荐将应用以及数据库一次性的迁移到云中。所有项目都应该分阶段来进行,阶段迁移的情况下就必须要将云资源与本地数据中心的资源互连互通。

要做到互连互通,有三种备选方案,互联网,专线直连(DX)和 VPN。从三个方面比较下这三种解决方案,安全,稳定性以及费用。DX 服务无疑是最优的一种解决方案,提供安全稳定的网络性能,高吞吐量。由于国内专线铺设所带来的高昂费用,所以在初期阶段,DX 并不是一个最优的。这里面互联网是最便宜的,因为本身数据中心就已经支付了这部分费用,只要保证云中的资源可以上互联网就可以了,但互联网面临的问题是网络依赖互联网,互联网的网络性能并不是可控的,另外一方面是互联网的安全性。VPN 呢是基于互联网的服务,虽然不能保证网络性通的可控,但可以做到数据的安全。

就以上比较而言,在初期阶段,VPN 无疑是一种高性比的安全以及节约成本的方案。考虑到目前北京区域并不支持硬件VPN的服务,即Global区域的VPN Connection。那么有没有可以替代的方案呢?答案是肯定的,一切问题都难不倒我们伟大的开源组织,开源方案如 OpenSwan (今天的主角),StrongSwan,Raccoon等等了。除了开源的解决方案外,还有一些商业解决方案,比如Sanfor 深信服,Hillstone 山石,Checkpoint , Cisco CSR1000v等也可以部署,有兴趣的可以与相应的软件提供商联系。

前面说了那么多关于VPN的各种软件,那么该如何选择呢?这里我们从使用上来划分下吧,将VPN主要划分为两类,一类是工作于客户端到服务端的模式,像OpenVPN,SSL VPN,L2TP,PPTP这些都是需要客户端主动发起连接,拨到Server端在两者之间建立一个逻辑上的隧道 (tunnel)进行通信。这种方式一般适用于个人到总部场景。服务器是无法主动发起连接到客户端。

另外一种就是站点到站点(site-to-site)的模式,像OpenSwan,StrongSwan, Raccoon 等软件,这种情况下两端会各有一个设备负责来建立两个站点之间安全通信的隧道,任何需要到对端的通信都会触发设备来建立安全隧道通信。

那么公司原有数据中心与云通信都是双向通信,所以站点到站点更合理。

实际上这里说的 VPN 即是指 IPsec VPN,IPsec 是一种工业标准,只要支持这种标准的设备都可以互相协商建立一个安全的隧道出来,比如支持的硬件设备有路由器,防火墙以及专业的 VPN 设备。

说了这么多,下面我们就以 AWS 端为 OpenSwan 与 Cisco 的路由器之间的配置为例。

场景及拓扑

拓扑如上图,AWS端建立一个VPC(CIDR:192.168.0.0/16),包含两个子网,一个可以上互联网的Public子网192.168.1.0/24以及私有子网Private 192.168.2.0/24。在公有子网上会配置一台OpenSwan实例与公司的Cisco设备做VPN连接。

OpenSwan的EIP地址为54.223.152.218 子网:192.168.1.0/24

Cisco设备的公网地址为54.223.170.5 子网:10.1.2.0/24

目标:实现AWS上私有子网192.168.2.0/24和数据中心10.1.2.0/24双向互通

详细配置步骤

1.配置 VPC 基础环境

1.1 创建 VPC

在AWS console界面点击VPC,在左侧点击“您的VPC”, 创建VPC

名称标签: MyVPC

CIDR块: 192.168.0.0/16

租赁:默认

1.2 创建子网

将鼠标点到子网,选择创建子网

标签名称:Public

VPC:选择第一步创建好的VPC

可用区:保持默认

CIDR块:192.168.1.0/24

以同样的方法创建一个192.168.2.0/24的子网

1.3 创建路由表

点击路由表,创建路由表

名称标签:PrivateRoute

VPC:选择1.1创建好的VPC

创建完成以后,点到刚刚创建好的路由表,在页面下列点击子网关联,点击编辑

在192.168.2.0/24的路由前打勾,点击保存。

1.4 创建 IGW

点击Internet网关,创建Internet网关

名称标签:MyIGW

创建完成,点击附加到VPC

选择新创建好的VPC

2. 启动并配置 VPN 实例

2.1 启动实例

到EC2页面,点击启动实例。选择Amazon Linux

在详细信息页中,网络请选择新创建的VPC

子网选择192.168.1.0/24

点击下一步,存储标签等按需配置

配置安全组,选择创建一个新的安全组

添加规则

自定义的UDP规则,端口500 来源任何位置

自定义的UDP规则,端口4500 来源任何位置

自定义协议, 协议 50 来源任何位置

所有流量 来源为 192.168.2.0/24

注意:一定要放行来自于192.168.2.0/24的流量,否则无法通信。

最后审核启动,启动时指定一个用于登陆实例的key文件,如果没有创建一个新的。

2.2 配置弹性 IP (EIP)

在EC2页面,左侧导航栏找到弹性IP,申请分配新地址,并将其关联到新创建的OpenSwan实例。这里申请到的为 54.223.152.218。

2.3 关闭源/目的检查

在EC2页面点击OpenSwan实例,右键选择联网,更改源/目标检查,点“是,请禁用”

3. 安装配置 OpenSwan

3.1 登录到实例安装 OpenSwan

如何登陆实例请参考如下文档:

https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/putty.html

登陆完成以后,运行如下命令安装OpenSwan

$ sudo yum -y install openswan

3.2 根据Cisco 参数来配置 OpenSwan

修改/etc/ipsec.conf去掉最后一行include /etc/ipsec.d/*.conf 的注释

$ sudo vim /etc/ipsec.conf

include /etc/ipsec.d/*.conf

 

Cisco路由器的配置如下:

crypto isakmp policy 10

encr aes

authentication pre-share

group 2

crypto isakmp key aws123 address 54.223.152.218

!

!

crypto ipsec transform-set OpenSwan esp-aes esp-sha-hmac

mode tunnel

!

!

!

crypto map OpenSwan 10 ipsec-isakmp

set peer 54.223.152.218

set transform-set OpenSwan

match address 100

!

!

interface GigabitEthernet1

ip address 54.223.170.5 255.255.255.252

ip mtu 1400

ip tcp adjust-mss 1360

crypto map OpenSwan

!

access-list 100 permit ip 10.1.2.0 0.0.0.255 192.168.2.0 0.0.0.255

ip route 0.0.0.0 0.0.0.0 54.223.170.6

根据cisco的配置创建OpenSwan的配置如下:

$ sudo vim /etc/ipsec.d/cisco.conf

conn cisco

authby=secret

auto=start

leftid=54.223.152.218

left=%defaultroute

leftsubnet=192.168.2.0/24

leftnexthop=%defaultroute

right=54.223.170.5

rightsubnet=10.1.2.0/24

keyingtries=%forever

ike=aes128-sha1;modp1024

ikelifetime=86400s

phase2alg=aes128-sha1

salifetime=3600s

pfs=no

配置解释:

leftid 标明本地对应公网IP

letftsubnet为本地子网

right为对端公网地址

rightsubnet为对端子网

ike为第一阶段参数

ikelifetime为第一阶段的生存时间

phase2alg为第二阶段参数

salifetime为第二阶段生存时间

结果如下图:

配置预共享密钥:

$ sudo vim /etc/ipsec.d/cisco.secrets

54.223.152.218  54.223.170.5: PSK “aws123”

启动openswan服务并做配置检查

$ sudo service ipsec start

$ sudo ipsec verify

3.3 修改系统参数

更改系统参数做IP转发并关闭重定向功能

编辑/etc/sysctl.conf内核配置文件,做如下修改

$ vim /etc/sysctl.conf

$ vim /etc/sysctl.conf

net.ipv4.ip_forward = 1

net.ipv4.conf.all.accept_redirects = 0

net.ipv4.conf.all.send_redirects = 0

net.ipv4.conf.default.send_redirects = 0

net.ipv4.conf.eth0.send_redirects = 0

net.ipv4.conf.default.accept_redirects = 0

net.ipv4.conf.eth0.accept_redirects = 0

配置完成以后,启用新的配置

$ sudo sysctl –p

3.4 更改 OpenSwan 的网卡 MSS 值

$ sudo iptables -t mangle -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1387

3.5 修改 VPC 私有子网路由表

找到VPC Console页面,在左侧点路由表,找到192.168.2.0/24关联的路由表(1.3中创建), 在页面下方点击路由,编辑

添加其他路由,

目标: 10.1.2.0/24

目标:OpenSwan实例ID (i-xxxxx)

4. 测试连通性

以上步骤都完成以后,就可以在192.168.2.0网段的实例进行测试了。使用 ping 测试到 10.1.2.x private 私有地址段的一个地址。

ping 10.1.2.3

检查 IPsec tunnel 状态:

$ sudo service ipsec status

IPsec running - pluto pid: 25674

pluto pid 25674

1 tunnels up

some eroutes exist

常见问题及排错

1.  IPsec Tunnel 没有正常建立

首先检查到对端 IP 是否可以通信,检查安全组是否放行 IKE 需要的端口 UDP 500。如果网络层没问题,检查各项参数配置是否有错误。

2. 隧道建立成功,但是无法进行通信

首先检查 IP forward 是否设置为 1?VPN 实例安全组是否放行了相应的策略?路由是否正确?NAT 是否影响?

3. NAT 问题

如果您的 CGW 配置了 NAT 与 VPN 工作,根据厂家不同对 VPN 包的处理顺序不一致,如果源 NAT 在 VPN 之前被处理了,因为源地址发生了改变,所以也就不会再被 VPN 处理,造成通信失败。像 Cisco 设备就需要做 NAT 的例外策略。主流的 Cisco ASA 就需要做相应修改,参考如下:

8.2 及以前的版本:

nat (inside) 0 access-list nat_exemption
access-list nat_exemption extended permit ip 192.168.1.0 255.255.255.0 10.0.0.0 255.255.255.0

8.3 及更新的版本:

object network obj-192.168.1.0

subnet 192.168.1.0 255.255.255.0

object network obj-10.0.0.0

subnet 10.0.0.0 255.255.255.0

nat (inside,any) source static obj-192.168.1.0 obj-192.168.1.0 destination static obj-10.0.0.0 obj-10.0.0.0 no-proxy-arp

如果您经过以上步骤还是不能成功搭建 VPN,AWS Support 提供专业化的技术支持,可根据您当前或计划的使用案例为您提供一套独特的工具和专业知识。建议您开案例联系Support 技术支持。

作者介绍:

侯晓鹏

亚马逊AWS云支持工程师,多年从事网络相关支持以及架构咨询工作,在加入 AWS 以前曾担任 Juniper 高级咨询专家,负责为企业网及运营商提供专业架构咨询及网络优化工作。现任亚马逊云支持工程师,AWS 认证 Direct Connect 服务专家。多次帮助大规模企业客户解决混合云复杂技术及架构问题。

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之前,从事电信核心网系统上云的方案设计及标准化推广 。

VPC中NAT的那点事

NAT就在那里

下图 是EC2实例通过IGW(Internet网关) 接入到Internet的示意图。熟悉AWS的读者会知道,这里EC2实例和Internet通信的两个方向上,实际上发生了如下的转换:

  • 从EC2实例发出的前往Internet的IP包,其源地址10.0.0.10在经过IGW时,会被转换为与实例关联的公网地址 54.232.0.1;
  • 从Internet发给54.232.0.1的IP包,经过IGW时其目的地址会转换为ENI对应的内网地址10.0.0.10并被送到 EC2实例;

可以看到,这里Internet网关就是起到实例的内网地址和公网地址一对一的基本 NAT(网络地址转换)的功能。

相比于没有NAT的场景,大部分的应用、软件不需要任何改变就能在基本NAT的场景下继续工作,例如基于HTTP协议的Web应用等;但是对于某些应用,例如FTP、VoIP等,网络地址转换会给应用带来一些意想不到的挑战。今天我们以历史悠久的FTP协议为例,来和大家探讨一下NAT给FTP这样的应用带来什么样的挑战,以及FTP应用和协议又是如何演进去适应它。

被动模式下的FTP

我们重温一下FTP的工作过程。客户端连接服务端TCP 21端口建立命令通道后,输入用户名密码完成登录;随后的每一次数据传输都需要另外建立数据通道进行; 如果数据通道由客户端发起,服务端接受,我们称之为被动模式;反之,如果数据通道由服务端发起,客户端接受,则称之为主动模式。

为简化讨论,我们以被动模式为例。

同一个私网内

我们在EC2实例10.0.0.10上搭建了一台FTP服务器,它监听在21端口。现在我们从同一个VPC里的另外一台EC2上运行FTP客户端;那么整个过程会很顺利。

从Internet访问

现在我们从位于Internet某处的一台PC上运行FTP客户端。

这里连接超时的原因显而易见,FTP服务端发送给客户端的IP地址是服务端的私有地址。位于Internet上的客户端无法建立与位于VPC内部的私有地址10.0.0.10直接通讯。

解决这个问题有多种方法,我们由简单到复杂分别叙述。

增强协议适配NAT

FTP协议针对NAT和其他因素,对协议进行了增强,提供了增强版的被动模式EPSV命令[1]。

下面的例子里,服务端不再显式指定IP地址,只提供数据通道的端口号。客户端默认与控制通道相同的IP地址建立数据通道。

可以看到,解决方案很优雅。实际上如果你在阅读本文的时候,绝大部分FTP服务端和客户端都已经实现了EPSV,而且优先使用它,所以FTP应用目前在EC2上是可以称之为开箱即用的。当然这需要客户端和服务端都支持增强的协议才能达成;如果我们不修改协议,能否解决这个问题呢。

放开那协议!我来!

有些时候,修改协议和实现需要多方协调和很长的时间才能完成。在RFC2428标准化之前,一些FTP实现就已经通过修改实现来适配基本NAT,而非修改协议。

以vsftpd为例,它允许通过配置文件vsftpd.conf中的配置项 pasv_address=54.232.0.1 告知服务端,在PASV被动模式下,应当指示客户端连接到配置项指定的IP(而不是服务端的私有IP)来适配基本NAT。

其他的一些常见应用例如VoIP类应用,也有类似的机制去适配基本NAT;例如引入STUN/TURN/ICE等方式[2]适配各种更加复杂的NAT穿越场景;但是针对部署在EC2上的基本NAT环境,也有通过实现上的简单调整,例如开源VoIP应用Asterisk就支持通过在配置文件/etc/asterisk/sip.conf里指定本机的公网地址和本地网段的方式来适配基本NAT。

nat=yes

externaddr=54.223.0.1

localnet=10.0.0.0/16

协议和实现我都不想动!

作为一枚任性的读者,如果您既不想动协议也不想动实现,这里笔者给读者介绍一种剑走偏锋的方式,读者若有兴趣,可以轻松愉快的在AWS上试一试,看看能否解决你的应用适配基本NAT。下面是一段shell脚本,当然是运行在Linux操作系统上的。

          #从EC2 实例元数据服务获取本实例的公网IP(如有)、私网IP

          public_ipv4=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`

          local_ipv4=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`

          #配置私网地址段,这里应为EC2实例所在VPC的地址范围

          local_net=10.0.0.0/16

          if [ “x${public_ipv4}” == “x” ]

          then

          echo “No public IPv4 address available for this instance, abort.”

          exit 1

          else

           #如果EC2实例的公网IP不为空,则将该公网地址添加到eth0上

          ip address add ${public_ipv4}/32 dev eth0

          #本地接受的连接,如果来源不是本VPC,那么将IP包的目的地址改写为公网IP

          iptables -t nat -A PREROUTING ! -s ${local_net} -d ${local_ipv4} -i eth0 -j DNAT –to ${public_ipv4}

          #本地发起的连接,如果出方向流量的源IP地址是公网地址,那么需要改写为私网IP

          iptables -t nat -A POSTROUTING -s ${public_ipv4} -o eth0 -j SNAT –to ${local_ipv4}

          fi

正常情况下,脚本执行完毕后,可以通过如下方式验证效果。

首先检查本实例的公网IP是否已经正确配置到eth0上。

~ # ip addr show dev eth0

eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000

link/ether 02:c7:6b:9b:d2:b6 brd ff:ff:ff:ff:ff:ff

inet 10.0.0.10/24 brd 10.0.0.255 scope global eth0

valid_lft forever preferred_lft forever

                  inet 54.232.0.1/32 scope global eth0

valid_lft forever preferred_lft forever

inet6 fe80::c7:6bff:fe9b:d2b6/64 scope link

valid_lft forever preferred_lft forever

可以看到,公有IP地址(54.232.0.1/32)已经成功添加到eth0接口。

然后检查iptables的NAT规则是否正确配置

~ # iptables -t nat -nvL

 

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)

pkts bytes target     prot opt in     out     source               destination

               0    0  DNAT       all  —  eth0   *       ! 10.0.0.0/16        10.0.0.10            to:54.223.74.106

Chain INPUT (policy ACCEPT 1 packets, 64 bytes)

pkts bytes target     prot opt in     out     source               destination

 

Chain OUTPUT (policy ACCEPT 3 packets, 222 bytes)

pkts bytes target     prot opt in     out     source               destination

 

Chain POSTROUTING (policy ACCEPT 3 packets, 222 bytes)

pkts bytes target     prot opt in     out     source               destination

              0     0 SNAT       all  —  *      eth0    54.223.74.106        0.0.0.0/0            to:10.0.0.1

从上面可以看到传入、传出数据包的数量以及IP地址在传入前,传出后的地址改写情况。

最后分别从VPC内部和Internet连接到服务,验证结果

~ $ ss -nt

State       Recv-Q Send-Q            Local Address:Port                       Peer Address:Port

ESTAB        0          72                   54.223.74.106:21                            119.xx.x.xx:52425

ESTAB        0      1272                   54.223.74.106:12081                      119.xx.x.xx:23710

ESTAB        0          72                   10.0.0.10:21                                     10.xx.x.xx:48361

ESTAB        0      1272                   10.0.0.10:12090                               10.xx.x.xx:32115

笔者在没有修改任何vsftpd的配置文件的前提下,通过上述脚本的运行和配置,同一个VPC内部的客户端和Internet客户端都能完成FTP被动模式的文件传输全流程。

值得一提的是,本方法仅供参考,不建议在生产环境中大规模使用,推荐的解决方案请参考前文关于协议适配和实现适配。

[1] FTP Extensions for IPv6 and NATs  https://tools.ietf.org/html/rfc2428
[2] NAT Traversal Practices for Client-Server https://tools.ietf.org/html/rfc6314
作者介绍:

丁成银

AWS 解决方案架构师,获得AWS解决方案架构师专业级认证和DevOps工程师专业级认证。负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云 服务在国内的应用和推广,在数字媒体、电信、互联网和游戏、企业混合IT等方面有着丰富的实践和设计经验。在加入AWS之前,历任数字媒体娱乐系统工程 师、宽带业务架构师、云解决方案架构师,负责数字媒体娱乐系统、云计算解决方案等服务的咨询和架构设计工作。

 

使用Docker封装IPSec安全网关

随着云成为新常态,越来越多的客户开始采用AWS云服务,使用VPN隧道安全的连接到AWS成为一个常见的场景。本文介绍一种仅需少量交互与配置即可与多个AWS VPC建立动态路由VPN连接并在各个互联VPC之间转发流量的方案。该方案主要使用了Docker、IPSec套件strongSwan、动态路由软件BIRD,并在此基础上,使用AWS SDK for Python( Boto 3)、docker-py等实现快速建立与AWS VPC的动态VPN。

项目中使用的Dockerfile、相关的shell脚本以及Python应用等源文件均已经在这里开放,做为一种快速部署Customer Gateway的方法,供各位读者参考。

本文假定读者从概念上理解AWS VPC、IPSec VPN以及动态路由协议BGP。如果希望了解更多如何与AWS VPC建立VPN连接的信息,读者可以参考 AWS VPC 网络管理员指南。

如何使用

我们从最基本的场景开始,假定您需要将本地网络与单个AWS VPC通过IPSec隧道互联。

图中Customer Gateway应为一台可以访问Internet且IP固定的 Linux服务器, 这台服务器将作为IPSec网关和BGP路由器,将内部网络与AWS VPC通过IPSec隧道和BGP动态路由协议连接起来。

在Customer Gateway上执行如下预备工作:

一、我们需要 预先安装和配置好docker引擎;

二、我们的脚本使用了Python和一些第三方库,所以需要安装Python 2.7或更新版本以及Python包管理工具,例如pip

三、通过pip安装如下软件包;

a. boto3 —— AWS SDK for Python,用于获取VPN连接的配置信息

b. xmltodict —— 便于python处理XML格式的数据

c. docker-py —— 用于连接docker engine并创建、运行容器

四、配置boto3连接AWS的 IAM凭证,需要注意使用的IAM用户需要拥有执行describe_vpn_connections API所需的权限。

$ cat  ~/.aws/credentials

[default]

aws_access_key_id = YOUR_KEY

aws_secret_access_key = YOUR_SECRET

建立连接

参照AWS VPC用户指南中关于“设置VPN连接”章节的指导,完成如下步骤:

步骤一、创建虚拟专用网关,附加到目标VPC并启用路由传播;

步骤二、创建客户网关,输入Customer Gateway的公网IP地址,选择动态路由,并输入65000作为本地网络的BGP ASN号;

步骤三、创建虚拟专用网关和客户网关之间的VPN连接,每个VPN连接包含两条相护冗余的VPN隧道;

步骤四、在Customer Gateway上执行peer.py 脚本,传入目标VPC所在的region名称和vpn连接id,该脚本将会调用AWS API下载指定的VPN连接的配置信息、然后连接Docker Engine创建cgw 容器并将关键参数作为环境变量传入容器;

步骤五、cgw容器会根据传入的环境变量完成自举并发起到AWS侧虚拟专用网关的2条动态路由VPN连接。

CGW容器的实现

正常的容器运行中的进程信息可见下图

可以看到容器中共有4个进程,其功能分别为:

一、cgw.sh 容器启动脚本,主要在容器开始运行时完成以下动作;

a. 根据传入的环境变量生成strongSwan、BIRD的配置文件

b.  配置virtual tunnel interface以便将两条ipsec隧道暴露给动态路由软件

c. 拉起strongSwan、BIRD

二、strongSwan守护进程,负责与虚拟专用网关协商和交换加密、解密密钥、调用Linux内核中IPSec相关的系统调用设定隧道;

三、BIRD守护进程;

a. 与虚拟专用网关的两个端点分别建立BGP邻居关系并以10秒的间隔持续检测对端是否健康

b. 与本地网络中其他路由器建立BGP邻居关系并将路由信息发布到本地网络和AWS VPC;实现本地网络与AWS VPC的互通

c. 当两条隧道中的一条由于某种原因发生故障,BIRD会检测到邻居状态的改变从而自动将流量切换到另外一条健康的隧道中去,从而实现了VPN连接的冗余

扩展性和可用性

一、如果需要与多个不同的VPC建立多条VPN连接,那么只需要重复前面建立连接的步骤在同一台服务器上创建多个cgw容器,分别建立与不同的虚拟专用网关的VPN连接即可。如下图所示

但是要做到不同VPC之间的流量互通,我们还需要在多个cgw容器之间建立iBGP邻居关系。传统的iBGP互联要求full mesh,这里我们为了简化部署和配置,可以在容器所在服务器上运行BIRD并将其配置为路由反射器,所有cgw容器都与路由反射器建立邻居关系并学习到其他容器、隧道的路由信息,从而实现多个VPN连接之间的流量互通。

二、如果需要保证高可用,需要在不同的VPN网关之间实现互为备份,那么可以通过运行两台物理服务器,各自建立与AWS VPC的VPN连接,通过动态路由协议来实现故障流量切换;

三、如果需要进一步增大吞吐量,超出单个服务器的可用带宽的情况下,我们可以将cgw容器分散到多个物理服务器上实现水平扩展;同样的,在服务器之间需要建立iBGP邻居关系并交换路由信息;

作者介绍:

丁成银

亚马逊AWS解决方案架构师,获得AWS解决方案架构师专业级认证和DevOps工程师专业级认证。负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广,在数字媒体、电信、互联网和游戏、企业混合IT等方面有着丰富的实践和设计经验。在加入AWS之前,历任数字媒体娱乐系统工程师、宽带业务架构师、云解决方案架构师,负责数字媒体娱乐系统、云计算解决方案等服务的咨询和架构设计工作。