【问题标题】:AWS Lambda Timeout when making external HTTPS Request发出外部 HTTPS 请求时的 AWS Lambda 超时
【发布时间】:2019-11-15 15:35:46
【问题描述】:

我需要在我的 AWS Lambda 项目中使用 Firebase Admin Java,但 Firebase Auth Admin 在尝试获取 Google 服务器中的公钥时会抛出 SocketTimeoutException。我知道 Firebase Admin 配置正确,因为我可以在 Tomcat 实例中本地运行它而无需担心。

然后我尝试向 https://postman-echo.com/get?foo1=bar1&foo2=bar2 之类的测试 API 发出 HTTPS 请求,它具有相同的行为,我也遇到了超时,这让我认为这是 Lambda 调用 HTTPS 的问题请求。

现在我知道了:

  1. 我的 lambda 已与 API Gateway 集成
  2. 我的 lambda 位于通过 Internet 网关访问 Internet 的子网中
  3. 我的 lambda 安全组是开放的
  4. 我知道这个问题发生在 HTTPS 请求上,我不确定纯 HTTP。这很难测试,因为我找不到不会自动从 HTTP 重定向到 HTTPS 的 API,而且我现在也不能自己推出。

为了完整起见,我将在这里留下我从 Firebase Admin Java 获得的 SocketTimeoutException,尽管我不确定这是 Firebase Admin 库中的问题还是 AWS Lambda + HTTPS 或两者一起出现的问题:

[main] 错误 com.example.project.filters.FirebaseAuthenticationFilter - 解析或验证令牌时出错 com.google.firebase.auth.FirebaseAuthException:验证时出错 签名。在 com.google.firebase.auth.FirebaseTokenVerifierImpl.checkSignature(FirebaseTokenVerifierImpl.java:160) 在 com.google.firebase.auth.FirebaseTokenVerifierImpl.verifyToken(FirebaseTokenVerifierImpl.java:92) 在 com.google.firebase.auth.FirebaseAuth$4.execute(FirebaseAuth.java:426) 在 com.google.firebase.auth.FirebaseAuth$4.execute(FirebaseAuth.java:423) 在 com.google.firebase.internal.CallableOperation.call(CallableOperation.java:36) 在 com.google.firebase.auth.FirebaseAuth.verifyIdToken(FirebaseAuth.java:388) 在 com.google.firebase.auth.FirebaseAuth.verifyIdToken(FirebaseAuth.java:362) 在 com.example.project.filters.FirebaseAuthenticationFilter.filter(FirebaseAuthenticationFilter.java:55) 在 org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:132) 在 org.glassfish.jersey.server.ContainerFilteringStage.apply(ContainerFilteringStage.java:68) 在 org.glassfish.jersey.process.internal.Stages.process(Stages.java:197) 在 org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:269) 在 org.glassfish.jersey.internal.Errors$1.call(Errors.java:272) 在 org.glassfish.jersey.internal.Errors$1.call(Errors.java:268) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:316) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:298) 在 org.glassfish.jersey.internal.Errors.process(Errors.java:268) 在 org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289) 在 org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256) 在 org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703) 在 com.amazonaws.serverless.proxy.jersey.JerseyHandlerFilter.doFilter(JerseyHandlerFilter.java:91) 在 com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:84) 在 com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:206) 在 com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler.handleRequest(JerseyLambdaContainerHandler.java:184) 在 com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler.handleRequest(JerseyLambdaContainerHandler.java:76) 在 com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:177) 在 com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:209) 在 com.example.project.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:39) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:350) 在 lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888) 在 lambdainternal.AWSLambda.startRuntime(AWSLambda.java:293) 在 lambdainternal.AWSLambda.(AWSLambda.java:64) 在 java.lang.Class.forName0(本机方法)在 java.lang.Class.forName(Class.java:348) 在 lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114) 原因: java.net.SocketTimeoutException:连接超时 java.net.PlainSocketImpl.socketConnect(Native Method) 在 java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) 在 java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) 在 java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) 在 java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) 在 java.net.Socket.connect(Socket.java:589) 在 sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:666) 在 sun.net.NetworkClient.doConnect(NetworkClient.java:175) 在 sun.net.www.http.HttpClient.openServer(HttpClient.java:463) 在 sun.net.www.http.HttpClient.openServer(HttpClient.java:558) 在 sun.net.www.protocol.https.HttpsClient.(HttpsClient.java:264) 在 sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:367) 在 sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191) 在 sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156) 在 sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050) 在 sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177) 在 sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:162) 在 com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:104) 在 com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981) 在 com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.refresh(GooglePublicKeysManager.java:172) 在 com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.getPublicKeys(GooglePublicKeysManager.java:140) 在 com.google.firebase.auth.FirebaseTokenVerifierImpl.isSignatureValid(FirebaseTokenVerifierImpl.java:226) 在 com.google.firebase.auth.FirebaseTokenVerifierImpl.checkSignature(FirebaseTokenVerifierImpl.java:152) ... 38 更多

【问题讨论】:

    标签: java aws-lambda firebase-authentication aws-api-gateway firebase-admin


    【解决方案1】:

    我的 lambda 位于通过 Internet 网关访问 Internet 的子网中

    单独的 Internet 网关不会提供驻留在 VPC 中的 Lambda 函数对 Internet 的访问。这是因为 VPC 内的 Lambda 函数不接收公共 IP 地址。您必须使用 NAT 网关为 VPC 内的 Lambda 函数提供 Internet 访问。

    【讨论】:

    • 谢谢马克,我发现这几个小时运行一个简单的 Lambda 来测试这个问题......我现在正在搜索的是是否有任何使用 NAT 的方法,我真的不知道该做什么每月支付 32 美元,我有一个小项目,而在巴西,这很贵。
    • 如果您的 Lambda 需要访问 VPC 内的资源以及 Internet 上的资源,则无法使用 NAT。
    • 这就是我害怕的...谢谢
    • 您可以将 EC2 实例配置为 NAT 实例,而不是使用 Amazon 的 NAT 网关,虽然它需要更多管理,但可能更便宜,并且您需要在自动扩展组中配置它或为了自动处理灾难恢复。
    • 我发现 AWS 实际上提供了一个准备成为 NAT 的 EC2 实例映像,它似乎比 t2.micro 便宜 3 倍,所以我可能至少现在会选择这个选项。
    猜你喜欢
    • 2019-10-06
    • 2019-02-07
    • 2021-07-23
    • 2021-02-28
    • 1970-01-01
    • 2020-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多