Amazon API Gateway在ELB和ECS集群前面

35
我想在应用负载均衡器前面放置一个亚马逊API网关,该负载均衡器将流量平衡到我的ECS集群,其中部署了所有微服务。使用API网关的动机是通过lambda函数使用自定义授权者。
系统图示:

enter image description here

在亚马逊的话中(https://aws.amazon.com/api-gateway/faqs/):“代理请求到后端操作也需要在Internet上公开访问”。这迫使我将ELB公开(面向Internet),而不是内部。然后,我需要一种方法来确保 API Gateway 能够在VPC之外访问ELB。
我的第一个想法是在API Gatway中使用客户端证书,但ELB似乎不支持它。
任何想法都将不胜感激!

2
我认为没有简单的解决方案。要么API网关不适合您,要么您需要做更多工作。解决方案包括在ALB之前放置HAProxy以验证客户端证书。或者在ALB之前放置Lambda,但这将需要缓冲整个响应,可能会减慢速度。或者如果可以的话,从API Gateway向ALB注入一个秘密头。这个秘密将在后端进行验证。我不建议使用IP白名单,因为API网关的IP范围不是静态的,可能会发生变化并破坏一些东西。 - doorstuck
感谢@doorstuck。我想避免集成像HAProxy这样的新组件。我猜这种情况(API网关,ELB,ECS集群)相当普遍。AWS没有提供开箱即用的解决方案吗? - Ricardo García Martín
API网关更适用于Lambda函数服务。当放置在托管服务的Docker容器前面时,我觉得它增加了太多的延迟和复杂性。我只使用API网关的代理部分,因此我使用另一个代理而不是API网关。我成功地使用了Zalando的Skipper。 但是,如果您想要使用授权者、CloudFront缓存等功能,那么也许API网关仍然是最好的选择。 - doorstuck
谢谢。我创建了一个Lambda来代理VPC内的请求,但我不喜欢这种方法,因为它增加了延迟和复杂性。最终,我用开源的TyK替换了Amazon API Gateway。 - Ricardo García Martín
8个回答

13

从推广的方式来看,这似乎是API网关技术中一个巨大的缺失部分。如果不能调用VPC内部面向服务器,它将严重限制其作为互联网访问身份验证前门的实用性。 Azure的API管理支持此功能 - 它可以接受来自互联网的请求并直接调用您的虚拟网络,否则该网络将被防火墙隔离。 在AWS下唯一似乎可行的方法是使用Lambdas,这增加了相当大的复杂性,特别是如果您需要支持各种二进制协议。


7

7
顺便说一下,最终我确实尝试了这个方法,是可以实现的,但并不是非常方便。首先,你只能让API网关与网络负载均衡器通信,而不能与应用程序负载均衡器通信。因此,如果你当前已经设置了外部面向应用程序负载均衡器,而网关需要与其通信,那么你需要将它们替换为网络负载均衡器(这意味着你会失去SSL终止和其他一些可能正在使用的选项),或者在应用程序负载平衡器前添加一个NLB,使其仅限于内部。此外,将现有路由从“HTTP”更改为“VPC链路”并不完全无缝。 - Dylan Nicholson
2
如何在ALB前设置NLB?有什么建议吗? - Joshua G. Edwards
3
如果你还感兴趣,这里有一篇博客文章链接 - Keenan Lawrence
感谢 @DylanNicholson 的神秘力量。 - kian
我无法告诉你,我们在决定API网关没有带来任何所谓的收益后将其丢弃了。 - Dylan Nicholson
显示剩余2条评论

5
我们决定使用一个头部来检查所有流量是否通过API Gateway。我们在应用程序的环境变量中保存一个密钥,并告诉API Gateway在创建API时注入该密钥。然后在我们的应用程序中检查该密钥。
以下是我们为此所做的内容:
在我们的基本控制器中,我们检查该密钥(我们只在网关后面拥有一个REST API)。
string ApiGatewayPassthroughHeader = context.HttpContext.Request.Headers["ApiGatewayPassthroughHeader"];

if (ApiGatewayPassthroughHeader != Environment.GetEnvironmentVariable("ApiGatewayPassthroughHeader"))
{
    throw new error;
}

在我们的swagger文件中(我们使用swagger.json作为API的来源)
"x-amazon-apigateway-integration": {
    "type": "http_proxy",
    "uri": "https://${stageVariables.url}/path/to/resource",
    "httpMethod": "post",
    "requestParameters": {
      "integration.request.header.ApiGatewayPassthroughHeader": "${ApiGatewayPassthroughHeader}"
    }
  },

在我们的Docker Compose文件中(我们正在使用Docker,但同样可以在任何设置文件中使用)
services:
  example:
      environment:
        - ApiGatewayPassthroughHeader=9708cc2d-2d42-example-8526-4586b1bcc74d

在构建时,我们从设置文件中获取密钥,并将其替换到swagger.json文件中。这样,我们就可以轮换设置文件中的密钥,API网关会更新以使用应用程序正在查找的密钥。


3
我知道这是一个旧问题,但我认为他们最近可能刚刚增加了支持。
"Amazon API Gateway宣布HTTP API已经正式上线,使客户能够轻松构建高性能的RESTful API,相比于API Gateway提供的REST API,成本可节省高达71%,延迟降低60%。随着此次发布,客户将能够利用几个新功能,包括路由请求到AWS Elastic Load Balancers(ELB)的能力,其中包括对AWS ALB的新支持以及在AWS CloudMap中注册的基于IP的服务。"

https://aws.amazon.com/about-aws/whats-new/2020/03/api-gateway-private-integrations-aws-elb-cloudmap-http-apis-release/


2
如果您使用VPC Link和网络负载均衡器,则可以实现。请参考此帖子:https://adrianhesketh.com/2017/12/15/aws-api-gateway-to-ecs-via-vpc-link/。具体步骤如下:
1. 创建连接到目标组(位于VPC中的实例)的内部网络负载均衡器 2. 在API Gateway控制台中,创建一个VPC链接,并将其链接到上面的NLB 3. 创建API Gateway端点,选择“VPC链接集成”,并将您的NLB内部URL指定为“端点URL”
希望这能帮到您!

如果我们只使用ECS,我们可以将哪个实例添加为目标组? - rashidcmb

2

哇哦,谢谢你提供这个信息! - undefined

2

为了通过私有链接将请求路由到ALB,ALB应该是内部的。在我的设置中,完全可以正常工作,无需在其前面放置NLB。

路由应该如下:

$default / GET(或POST或您想要使用的任何其他方法) 集成应附加到所有路径$default和GET / POST / ANY等


1

目前没有办法将API Gateway放在私有ELB的前面,所以您是正确的,它必须面向Internet。我能想到的最好的解决方法是将ELB置于TCP通过模式,并在ELB后面的终端主机上终止客户端证书。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接