AWS 实例配置文件不适用于 Spring Cloud AWS

AWS Instance Profile doesn't work with Spring Cloud AWS

我有一个小型 Spring 启动应用程序,使用 Spring Cloud AWS (1.0.0.RELEASE) 访问 SQS 队列。它正在部署在设置了实例配置文件的 EC2 实例上。看起来 AWS 方面的事情正在运作,因为我可以访问两个相关的元数据链接:iam/infoiam/security-credentials/role-name,它们确实包含正确的信息。可以肯定的是,我使用了 aws cmdline 实用程序 (aws sqs list-queues),它确实有效,所以我想设置没问题。但是,当应用程序启动时,它会读取 application.properties(其中包含行 cloud.aws.credentials.instanceProfile=true),然后丢弃以下警告:com.amazonaws.util.EC2MetadataUtils: Unable to retrieve the requested metadata 并最终抛出以下异常:

Caused by: com.amazonaws.AmazonServiceException: The security token included in the request is invalid. (Service: AmazonSQS; Status Code: 403; Error Code: InvalidClientTokenId; Request ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
        at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1071)
        at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:719)
        at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:454)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:294)
        at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2291)
        at com.amazonaws.services.sqs.AmazonSQSClient.getQueueUrl(AmazonSQSClient.java:516)
        at com.amazonaws.services.sqs.buffered.AmazonSQSBufferedAsyncClient.getQueueUrl(AmazonSQSBufferedAsyncClient.java:278)
        at org.springframework.cloud.aws.messaging.support.destination.DynamicQueueUrlDestinationResolver.resolveDestination(DynamicQueueUrlDestinationResolver.java:78)
        at org.springframework.cloud.aws.messaging.support.destination.DynamicQueueUrlDestinationResolver.resolveDestination(DynamicQueueUrlDestinationResolver.java:37)
        at org.springframework.messaging.core.CachingDestinationResolverProxy.resolveDestination(CachingDestinationResolverProxy.java:88)
        at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.start(AbstractMessageListenerContainer.java:295)
        at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.start(SimpleMessageListenerContainer.java:38)
        at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:173)
        ... 17 common frames omitted

...这意味着由于某种原因 Spring Cloud AWS 未获取实例配置文件凭证。我在 com.amazonaws.request 上启用了 debug 日志级别,看起来发送请求时没有访问密钥和秘密密钥。

DEBUG --- com.amazonaws.request                    : Sending Request: POST https://sqs.eu-west-1.amazonaws.com / Parameters: (Action: GetQueueUrl, Version: 2012-11-05, QueueName: xxxxxxxxxxxxx, ) Headers: (User-Agent: aws-sdk-java/1.9.3 Linux/3.14.35-28.38.amzn1.x86_64 Java_HotSpot(TM)_64-Bit_Server_VM/25.45-b02/1.8.0_45 AmazonSQSBufferedAsyncClient/1.9.3, )

有人知道我遗漏了什么或至少有任何提示如何进一步调试吗?

编辑: 在浏览了一些 spring-cloud-aws 代码之后,我有点前进了。与 jar 捆绑在一起的配置文件 application.properties 有一些 accessKeysecretKey 的文本值。我的自定义 application.properties 没有这些属性,这可能导致 spring 使用捆绑文件中的值作为默认值。我将它们包含在空值中,这将异常更改为 com.amazonaws.AmazonClientException: Unable to load AWS credentials from any provider in the chain。 AWS SDK 似乎配置了 DefaultProviderChain,但它仍然无法获取实例配置文件凭证。

这个问题的解决方案来自两个截然不同的事实。

  1. 将仅使用实例配置文件凭据,如果 application.properties 已将 instanceProfile 属性 设置为 true accessKey 设置为 null (ContextCredentialsAutoConfiguration).

  2. 即使您将提供自定义 application.properties 文件,Spring 也会读取与应用程序 jar 捆绑在一起的 application.properties 文件(如果它确实存在)。如果是这样的话,两个文件的属性将加起来创建一个执行环境。我怀疑首先解析捆绑文件,然后再解析自定义文件,覆盖捆绑文件中存在的任何 属性。

在我的例子中,捆绑的 application.properties 有 accessKey 和 secretKey 占位符(带有假值),只要开发人员想要在 EC2 环境之外进行一些测试,就会填写这些占位符。这使得 accessKey 不为空,因此排除了实例配置文件路径。我刚刚从 jar 中删除了 application.properties 文件并解决了问题。

cloud:
  aws:
    credentials:
      accessKey:
      secretKey:
      instanceProfile: true
      useDefaultAwsCredentialsChain: true

如果您使用的是最新的 (2.X.X) Spring AWS 云,这就可以了。