控制AWS上的无服务器网络应用流量

224 阅读6分钟

aerial photo of buildings and roads

06 五月 2022控制AWS上的无服务器Web应用流量

发布者:Aaron Brown

在最近的一个项目中,客户问我们是否有可能使用无服务器技术来托管React应用,同时确保流量不会离开他们的VPC和企业网络。

在这篇文章中,我将谈谈我们是如何实现这一目标的,以及事实证明,这比我们最初想象的要困难得多。

但为什么呢?

客户想要无服务器,因为他们不希望管理服务器。他们当然不希望在EC2实例上托管Apache httpd之类的东西。他们也不想在VPC中使用带有负载均衡器的ECSEKS集群。这并不是不合理的。如果有其他选择,为什么要管理用于托管网络服务器和提供静态资产的基础设施呢?

通常情况下,在这种情况下,我们建议客户通过AWS CloudFront提供资产,并在API GatewayLambda中托管后端(关于我们如何使用这些服务作为构建Web应用的更广泛技术套件的一部分,请参阅Ben Teese关于TGRS栈的博文)来实现无服务器。

但不幸的是,即使我们用AWS WAF白名单来保护Cloudfront分布,Cloudfront也不会对这个特定的客户起作用。这是因为使用CloudFront意味着流量必须离开他们的企业网络,这违反了他们严格的安全控制和合规要求。

那么,我们可以怎么做呢?

背景介绍

在我们进一步讨论之前,我应该先给你提供一点关于网络设置的信息。客户有一个分割良好的企业网络,包括一个使用Transit Gateway连接到中央服务AWS账户的内部网络。包含应用程序的AWS账户及其VPC随后被窥视到这个共享服务账户,并在服务账户中设置了适当的Route 53DNS转发和路由表。来自内部用户的流量通常像这样流经这一安排。

架构图概述了内部用户到达我们网络应用的理想流量

请注意,没有未经过滤的公共互联网访问,也绝对没有从互联网回到网络的访问。

入门

为了阻止从公共互联网访问我们的无服务器后端,我们只需将我们的API网关端点私有化。因此,随着CloudFront不再用于前端,我们想知道如果我们尝试通过一个私有的API Gateway端点从S3提供静态前端文件会发生什么。

为了做到这一点,我们用{proxy+} 关键字配置了API Gateway,以便通过所有子路径传递到S3。这很费事,但最后还是成功了。那么,问题解决了吗?

不完全是。API Gateway的一个缺点是,端点有随机和任意的URL分配给它们。虽然这对后端来说不是问题,但对前端来说就不太妙了。要求终端用户在他们的浏览器中输入一个随机生成的URL,这似乎有点不合理。

起初,解决这个问题似乎很简单,因为API Gateway有一个自定义域的功能。不幸的是,深入研究一下文档,发现它不支持私有API。

AWS文档的摘录,显示API网关的自定义域功能不支持我们的用例。

那么,我们还能如何获得一个自定义域名呢?我们的想法是在VPC中使用一个应用负载平衡器或代理,它可以处理从用户到API Gateway的调用。不幸的是,你不能将传统的或应用的负载平衡器直接连接到API Gateway(可能有很好的理由)。因此,我们需要在负载平衡器和API网关之间设置一些东西。

进入VPC端点

VPC端点几乎和它听起来一样:一个绑定到VPC的端点,可以用来访问AWS服务。可以为一个私有的API网关端点设置一个VPC端点,所以我们就这样做了。然后我们把我们的负载平衡器指向一个包含VPC端点IP地址的目标组。最终的结果看起来有点像这样。

使用网络负载平衡器访问API网关的临时尝试

唯一的问题是,它仍然没有工作!这是不可能的。经过一点点的探索,我们意识到,虽然我们的请求确实通过负载均衡器被转发到API Gateway,但API Gateway不知道我们是谁。因此,它只是忽略了这些请求。

为了解决这个问题,我们为一个用户友好的自定义域名添加了一个Route 53条目,以及一个指向负载均衡器的CNAME条目。

通过自定义域名访问API Gateway的最终解决方案,流量不会离开VPC

它成功了!来自内部网络用户的流量将通过中转网关到达负载均衡器,然后通过VPC端点到达API网关。在这一点上,唯一要做的是添加一个API Gateway方法,将/ 映射到我们的S3 Bucket中的/index.html ,模拟普通Web服务器中重写规则的作用。

限制

这种方法有几个限制。

首先,API Gateway限制了通过它返回的文件的大小为10MB。然而,对于一个网络应用来说,这并不是一个太大的问题。任何现代前端构建工具的部分工作是将一个大的应用程序分解成可以通过网络传递并由浏览器解释的小块,而不会让用户等待太长时间。这些块通常远远小于10Mb。

其次,值得注意的是,你是按照API网关收到的请求数量来支付的。然而,你通常是按100万个请求的批次付费。因此,除非你有成千上万的内部用户,否则通过API网关为你的前端提供服务的成本仍然有可能被为你的后端提供服务的成本所掩盖。

第三,如果你使用CloudFormation自动设置这个堆栈,你可能需要创建一个自定义资源来抓取API Gateway VPC端点的IP地址,这样你的负载均衡器就可以配置它们了。

最后,在理论上,VPC端点的IP地址有可能随着时间的推移而改变,这意味着你的网络负载平衡器配置可能会突然中断。在实践中,我还没有看到这种情况发生,我有的VPC端点已经运行了十二个月以上。然而,根据你的应用程序的关键程度,你可能希望在cron时间表上添加一个AWS Lambda函数,以确保最新的VPC端点IP地址始终是负载平衡器目标组的一部分。

总结

这是一个推荐的模式吗?可能不是。这当然比我们使用的典型的Cloudfront方法要复杂得多。但是,如果你有严格的合规性需求,这种方法仍然可以让你获得无服务器架构的许多好处,同时将你的所有流量保持在一个特定的网络中。如果你有兴趣自己尝试,这里有一个云计算模板,应该可以帮助你指出正确的方向。

标签。

aws,cloudformation,serverless

亚伦-布朗

aaron.brown@shinesolutions.com