Haproxy从AWS API Gateway

时间:2016-05-26 21:41:52

标签: amazon-web-services ssl amazon-ec2 haproxy aws-api-gateway

我已经使用AWS API Gateway设置了一个基本API,我想将我的端点链接到我在EC2实例上运行的服务(使用" HTTP代理"集成类型)。我已经读过为了锁定我的EC2服务器只接受来自API网关的流量,我基本上有以下两种选择之一:

  1. 将EC2实例粘贴在VPC后面并使用具有VPC权限的Lambda函数(而不是HTTP代理)作为"传递"对于API请求
  2. 在API网关中创建客户端证书,使用该证书发出后端请求,并验证EC2实例上的证书。
  3. 我想使用#2的变体,而不是在EC2服务实例本身上验证证书,我想在另一个运行Haproxy的实例上进行验证。我已经使用Haproxy设置了第二个EC2实例,并将其指向我的另一个实例作为后端。我已经锁定了我的服务实例,因此它只接受来自Haproxy实例的请求。这一切都有效。我一直在努力弄清楚的是如何在Haproxy机器上验证AWS Gateway Client证书(我已生成)。我已经完成了大量的谷歌搜索,并且令人惊讶地没有关于如何做到这一点的零信息。几个问题:

    1. 我读过的所有内容似乎都暗示我需要在Haproxy机器上生成SSL服务器证书并在配置中使用这些证书。我是否必须这样做,或者我是否可以在不生成任何其他证书的情况下验证AWS客户端证书?
    2. 我所做的阅读建议我需要生成一个CA,然后使用该CA生成服务器和客户端证书。如果我确实需要生成服务器证书(在Haproxy机器上),如果我无法访问亚马逊用于创建网关客户端证书的CA,我该如何生成它们?根据我的说法,我只能访问客户端证书本身。
    3. 这里有任何帮助吗?

      解决方案更新

      1. 首先,我必须将我的HAproxy版本升级到v1.5.14,这样才能获得SSL功能
      2. 我最初尝试使用letsencrypt生成官方证书。虽然我能够让API网关使用此证书,但我无法在API网关接受的HAproxy机器上生成letsencrypt证书。该问题表现为"内部服务器错误"来自API网关的响应以及"一般SSLEngine问题"在详细的CloudWatch日志中。
      3. 然后我从Gandi购买了一个通配符证书,并在HAproxy机器上尝试了这个,但最初遇到了完全相同的问题。但是,我能够确定我的SSL证书的结构不是API网关想要的。我用Google搜索并在此处找到了Gandi链: https://www.gandi.net/static/CAs/GandiStandardSSLCA2.pem 然后我按如下方式构建了我的SSL文件:
      4. -----BEGIN PRIVATE KEY-----
        # private key I generated locally...
        -----END PRIVATE KEY-----
        -----BEGIN CERTIFICATE-----
        # cert from gandi...
        -----END CERTIFICATE-----
        # two certs from file in the above link
        

        我保存了这个新的PEM文件(如haproxy.pem)并在我的HAproxy前端绑定语句中使用它,如下所示:

        bind :443 ssl crt haproxy.pem verify required ca-file api-gw-cert.pem
        

        上述绑定语句中的api-gw-cert.pem是一个文件,其中包含我在API网关控制台中生成的客户端证书。现在,HAproxy机器可以正确阻止来自除网关之外的任何流量。

2 个答案:

答案 0 :(得分:1)

  

我所做的阅读建议我需要生成一个CA,然后使用该CA生成服务器和客户端证书。

这是一种方法,但在这种情况下并不适用。

您的HAProxy需要配置由受信任的CA签署的有效SSL证书 - 而不是签署客户端证书的证书,而不是您创建的证书。它必须是由公共可信CA签名的证书,其根证书位于API网关后端系统的信任库中... 与您的Web基本相同浏览器信任,但可能是一个子集。

正如您的网络浏览器不会向拥有自签名证书的服务器发送SSL而不会发出必须绕过的警告,但API网关的后端不会与不受信任的证书进行协商(以及没有旁路)。

我只想说,在试图让它使用客户端证书之前,您需要让API Gateway通过TLS 与您的HAProxy通信,否则您将引入太多未知数。另请注意,您无法使用Amazon Certificate Manager证书,因为这些证书仅适用于CloudFront和ELB,它们都不会直接支持客户端证书。

HAProxy使用API​​网关后,您需要将其配置为对客户端进行身份验证。

您的ssl声明中需要verify requiredbind,但无法验证SSL客户端证书

  

我只能从我能说的内容中访问客户端证书。

这就是你所需要的一切。

bind ... ssl ... verify required ca-file /etc/haproxy/api-gw-cert.pem

SSL证书本质上是一个信任层次结构。树顶部的信任是明确的。通常,CA是明确信任的,并且它已签名的任何内容都是隐式信任的。 CA"担保"它签署的证书......对于证书,它使用CA属性集进行签名,CA属性集也可以在其下签署证书,从而扩展了隐含的信任。

但是,在这种情况下,您只需将客户端证书作为CA文件放入,然后将客户端证书"保证为" ...本身。呈现相同证书的客户端是受信任的,其他任何人都是断开连接的。当然,仅拥有证书对于客户端与您的代理进行通信是不够的 - 客户端还需要API网关所具有的匹配私钥。

因此,请考虑这两个单独的要求。首先通过TLS获取API网关与您的代理进行通信...之后,根据客户端证书进行身份验证实际上是更容易的部分。

答案 1 :(得分:0)

我认为您正在混淆服务器证书和客户端证书。在这种情况下,API Gateway是客户端,HAProxy是服务器。您希望HAProxy验证API Gateway发送的客户端证书。 API Gateway将为您生成证书,您只需配置HAProxy即可验证其处理的每个请求中是否存在证书。

我猜你可能正在查看他们告诉你生成客户端证书的this tutorial,然后配置HAProxy以验证该证书。由于API Gateway正在为您生成证书,因此可以跳过该教程的“生成证书”部分。

您只需单击API网关中的“生成”按钮,然后复制/粘贴它所呈现的证书的内容,并将其保存为HAProxy服务器上的.pem文件。现在我不是一个大的HAProxy用户,但我认为从该教程中获取HAProxy配置的示例如下所示:

case IS_BOOL:
            if (type != BP_VAR_UNSET && Z_LVAL_P(container)==0) {
                goto convert_to_array;
            }
            /* break missing intentionally */

        default:
            if (type == BP_VAR_UNSET) {
                zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
                result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
                PZVAL_LOCK(EG(uninitialized_zval_ptr));
            } else { // Gets here when boolean value equals true.
                zend_error(E_WARNING, "Cannot use a scalar value as an array");
                result->var.ptr_ptr = &EG(error_zval_ptr);
                PZVAL_LOCK(EG(error_zval_ptr));
            }
            break;