spring-attic / spring-cloud-aws

All development has moved to https://github.com/awspring/spring-cloud-aws Integration for Amazon Web Services APIs with Spring
https://awspring.io/
Apache License 2.0
589 stars 376 forks source link

Secrets Manager & Spring Boot Cloud Stream #782

Closed jklap closed 2 years ago

jklap commented 2 years ago

Type: Bug

Component: Secrets Manager (and I think Parameter Store too)

Describe the bug Spring Boot: 2.5.2 Spring Boot Cloud AWS: 2.3.1 Spring Cloud Stream: 3.1.1 Spring Kafka: 2.7.3

It looks like there is a problem with use of Spring Cloud Stream and Spring Boot AWS Secrets Manager.

We have a secret being pulled in via spring.config.import: aws-secretmanager:<secret_name>

If I run this with a bare-bones application, ie basically an empty Spring Boot application with a dummy API, this works fine and the secret is fetched and I can inject it as needed.

But when we add Spring Cloud Stream to the mix we get an error during startup complaining that it can not register an object under the same bean name (full exception below).

It seems as the root cause of this issue is that Spring Cloud Stream is creating a child application context in it's DefaultBinderFactory.getBinderInstance() which then triggers the CloseListener() added in AwsSecretsManagerConfigDataLocationResolver.registerAndPromoteBean() which attempts to register a singleton bean "configDataAWSSecretManager" BUT is then failing because there was already a bean by that name registered (ie I'm guessing in the parent application context but not quite sure??). Note that the bean it's attempting to register looks to be the same bean as already registered based on the Object identifier noted in the exception message.

A quick glance at the code in AwsParameterStoreConfigDataLocationResolver seems to have very similar code and hence likely the same problem.

Snippets from the errors/exceptions/stack traces below:

java.lang.IllegalStateException: Could not register object [com.amazonaws.services.secretsmanager.AWSSecretsManagerClient@365bfc5f] under bean name 'configDataAWSSecretsManager': there is already object [com.amazonaws.services.secretsmanag
er.AWSSecretsManagerClient@365bfc5f] bound
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.registerSingleton(DefaultSingletonBeanRegistry.java:124)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerSingleton(DefaultListableBeanFactory.java:1138)
        at io.awspring.cloud.autoconfigure.secretsmanager.AwsSecretsManagerConfigDataLocationResolver.lambda$registerAndPromoteBean$1(AwsSecretsManagerConfigDataLocationResolver.java:113)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
        at org.springframework.boot.DefaultBootstrapContext.close(DefaultBootstrapContext.java:133)
        at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:405)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:337)
        at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:144)
        at org.springframework.cloud.stream.binder.DefaultBinderFactory.getBinderInstance(DefaultBinderFactory.java:326)
        at org.springframework.cloud.stream.binder.DefaultBinderFactory.doGetBinder(DefaultBinderFactory.java:182)
        at org.springframework.cloud.stream.binder.DefaultBinderFactory.getBinder(DefaultBinderFactory.java:143)
        at org.springframework.cloud.stream.function.FunctionConfiguration$FunctionToDestinationBinder.determineTargetProtocol(FunctionConfiguration.java:600)
        at org.springframework.cloud.stream.function.FunctionConfiguration$FunctionToDestinationBinder.createFunctionHandler(FunctionConfiguration.java:552)
        at org.springframework.cloud.stream.function.FunctionConfiguration$FunctionToDestinationBinder.bindFunctionToDestinations(FunctionConfiguration.java:536)
        at org.springframework.cloud.stream.function.FunctionConfiguration$FunctionToDestinationBinder.afterPropertiesSet(FunctionConfiguration.java:401)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
07-09-2021:15:38:41.043 [main] WARN  org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext->refresh():591 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'functionInitializer' defined in class path resource [org/springframework/cloud/stream/function/FunctionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Could not register object [com.amazonaws.services.secretsmanager.AWSSecretsManagerClient@365bfc5f] under bean name 'configDataAWSSecretsManager': there is already object [com.amazonaws.services.secretsmanager.AWSSecretsManagerClient@365bfc5f] bound
07-09-2021:15:38:42.013 [main] INFO  org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener->logMessage():136 -
07-09-2021:15:38:41.043 [main] WARN  org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext->refresh():591 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'functionInitializer' defined in class path resource [org/springframework/cloud/stream/function/FunctionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Could not register object [com.amazonaws.services.secretsmanager.AWSSecretsManagerClient@365bfc5f] under bean name 'configDataAWSSecretsManager': there is already object [com.amazonaws.services.secretsmanager.AWSSecretsManagerClient@365bfc5f] bound
07-09-2021:15:38:42.013 [main] INFO  org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener->logMessage():136 -
neiljbrown commented 2 years ago

Hi, I believe this is a duplicate of https://github.com/awspring/spring-cloud-aws/issues/108, which reports the same issue for Spring Cloud AWS' SSM Param Store integration (albeit for earlier versions of Boot and Spring Cloud than you're using). As per that ticket, the issue has been fixed (see https://github.com/awspring/spring-cloud-aws/pull/142) and is due to be included in the next maintenance release of 2.3.x.

maciejwalkowiak commented 2 years ago

Thanks @neiljbrown for investigating. Indeed, this looks like the same issue. 2.3.2 will be released in upcoming weeks.