无法从 Lambda 检索 AWS 机密 运行 Java

Unable to retrieve AWS Secrets from Lambda running Java

我正在编写一个 AWS Lambda 函数来处理来自 discord 的请求。我将我的不一致值存储在 AWS SecretsManager 中并需要检索它们以便我可以验证请求。

我将我的 lambda 设置为在 30 秒后超时,当我的 lambda 运行时超时并且永远不会获得机密值。我 运行 在我的 IDE 中使用相同的代码,它能够获取值。我什至承担了我的 lambda 的角色,并且也能够在我的 IDE 中执行代码。 lambda 角色具有以下权限:

secretsmanager:GetSecretValue, secretsmanager:DescribeSecret, secretsmanager:ListSecrets

我什至给了 lambda 角色读取秘密值的权限。有人知道为什么它在 lambda 中超时而没有获得价值吗?这是我的 lambda 处理程序 class.

public class HandlerStream implements RequestHandler<DiscordEventRequest, DiscordEventResponse> {
  DiscordSecrets discordSecrets;
  Gson gson = new GsonBuilder().setPrettyPrinting().create();

  @Override
  public DiscordEventResponse handleRequest(DiscordEventRequest event, Context context) {
    LambdaLogger logger = context.getLogger();

    logger.log(String.format("Received Event: %s", gson.toJson(event)));
    try {
      getDiscordSecrets(logger);

      DiscordEventResponse response = new DiscordEventResponse();
      switch (event.getJsonBody().getType()) {
        case 1:
          response.setType(1);
      }

      return response;
    } catch (Throwable ex) {
      logger.log("Exception occurred when executing lambda: " + ex.getMessage());
    }
   throw new RuntimeException("[UNAUTHORIZED] invalid state detected");
  }

  private DiscordSecrets getDiscordSecrets(LambdaLogger logger) {
    if (discordSecrets == null) {
      String tokenName = System.getenv("discordToken");

      logger.log("Token Name " + tokenName);

      AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().build();

      GetSecretValueRequest request = new GetSecretValueRequest().withSecretId(tokenName);

      GetSecretValueResult response = client.getSecretValue(request);

      String secret;

      logger.log("Got secret value");

      if (response.getSecretString() != null) {
        secret = response.getSecretString();
      } else {
        secret = new String(Base64.getDecoder().decode(response.getSecretString().getBytes(StandardCharsets.UTF_8)));
      }
      discordSecrets = gson.fromJson(secret, DiscordSecrets.class);
      logger.log("Discord Secrets " + gson.toJson(discordSecrets));
    }
    return discordSecrets;
  }
}

这是从 lambda 返回的内容(我将其更改为 5 秒以便更快超时,但它也在 30 秒后超时)

2021-09-28T00:11:12.827-05:00   START RequestId: e5e211d0-9307-4609-9939-ff54f876e516 Version: $LATEST
2021-09-28T00:11:13.321-05:00   Received Event: { "jsonBody": { "type": 1, "version": 0 } }
2021-09-28T00:11:13.321-05:00   Token Name DiscordToken
2021-09-28T00:11:17.842-05:00   END RequestId: e5e211d0-9307-4609-9939-ff54f876e516
2021-09-28T00:11:17.842-05:00   REPORT RequestId: e5e211d0-9307-4609-9939-ff54f876e516 Duration: 5005.29 ms Billed Duration: 5000 ms Memory Size: 128 MB Max Memory Used: 102 MB Init Duration: 492.26 ms
2021-09-28T00:11:17.842-05:00   2021-09-28T05:11:17.833Z e5e211d0-9307-4609-9939-ff54f876e516 Task timed out after 5.01 seconds

它永远不会达到“获得秘密值”,也不会抛出异常。它所做的一切都等到 lambda 最终超时。

如有任何帮助,我们将不胜感激

更新 我更新了我的 lambda 以使用客户端的 v2,如下所示

private DiscordSecrets getDiscordSecrets(LambdaLogger logger) {
    if (discordSecrets == null) {
      String tokenName = System.getenv("discordToken");

      logger.log("Token Name " + tokenName);
      logger.log("Creating Client");
      SecretsManagerClient client = SecretsManagerClient.builder().region(Region.US_EAST_2).build();
      logger.log("Done creating client");
      String secret;

      GetSecretValueRequest request = GetSecretValueRequest.builder().secretId(tokenName).build();
      GetSecretValueResponse response = client.getSecretValue(request);

      logger.log("Got secret value");

      if (response.secretString() != null) {
        secret = response.secretString();
      } else {
        secret = new String(Base64.getDecoder().decode(response.secretBinary().asByteBuffer()).array());
      }
      discordSecrets = gson.fromJson(secret, DiscordSecrets.class);
      logger.log("Discord Secrets " + gson.toJson(discordSecrets));
    }
    return discordSecrets;
  }

看起来它正在尝试创建客户端。因为它在 Done creating client 发生之前超时。 IT 也一直在用旧方法获取客户。

故障排除步骤:

  1. 创建客户端时请指定地区。
AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().withRegion(Regions.<YOUR_REGION>).build();

请参考:https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/secretsmanager/AWSSecretsManagerClientBuilder.html

  1. 如果这不起作用并且 lambda 仍然超时,请为 SecreteManager 服务定义一个 VPC 端点。

请参考:https://heathivie.com/2020/08/13/aws-lambda-and-secrets-manager-timeout/

问候 阿米特

我想通了这个问题。问题是 Java Lambda 需要时间来启动然后初始化导致时间的 SecretsManager 客户端。

我最终将客户端设为静态

public class HandlerStream implements RequestStreamHandler {
  static SecretsManagerClient client = SecretsManagerClient.builder().build();
  ...
}

甚至在那之后我遇到了内存不足的异常,所以我将 lambda 的内存增加到 256,这似乎解决了问题。由于某些原因,lambda 在执行时使用了 146 mb 的内存。我不知道这是否是由于它如何处理 java 或不是。