Skip to content

Commit

Permalink
Autoconfigure SecretsManagerClient event when config import is not used.
Browse files Browse the repository at this point in the history
Fixes #1016
  • Loading branch information
maciejwalkowiak committed Mar 22, 2024
1 parent 02c0f97 commit 1da30c4
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.awspring.cloud.autoconfigure.config.secretsmanager;

import io.awspring.cloud.autoconfigure.core.AwsClientBuilderConfigurer;
import io.awspring.cloud.autoconfigure.core.AwsClientCustomizer;
import io.awspring.cloud.autoconfigure.core.AwsConnectionDetails;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder;

/**
* {@link EnableAutoConfiguration Auto-Configuration} for Secrets Manager integration.
*
* @author Maciej Walkowiak
* @since 3.2.0
*/
@AutoConfiguration
@EnableConfigurationProperties(SecretsManagerProperties.class)
@ConditionalOnClass({SecretsManagerClient.class})
@AutoConfigureAfter({CredentialsProviderAutoConfiguration.class, RegionProviderAutoConfiguration.class})
@ConditionalOnProperty(name = "spring.cloud.aws.secretsmanager.enabled", havingValue = "true", matchIfMissing = true)
public class SecretsManagerAutoConfiguration {

@ConditionalOnMissingBean
@Bean
public SecretsManagerClient secretsManagerClient(SecretsManagerProperties properties,
AwsClientBuilderConfigurer awsClientBuilderConfigurer,
ObjectProvider<AwsClientCustomizer<SecretsManagerClientBuilder>> customizer,
ObjectProvider<AwsConnectionDetails> connectionDetails) {
return awsClientBuilderConfigurer.configure(SecretsManagerClient.builder(), properties, connectionDetails.getIfAvailable(),
customizer.getIfAvailable()).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ io.awspring.cloud.autoconfigure.sns.SnsAutoConfiguration
io.awspring.cloud.autoconfigure.sqs.SqsAutoConfiguration
io.awspring.cloud.autoconfigure.dynamodb.DynamoDbAutoConfiguration
io.awspring.cloud.autoconfigure.config.secretsmanager.SecretsManagerReloadAutoConfiguration
io.awspring.cloud.autoconfigure.config.secretsmanager.SecretsManagerAutoConfiguration
io.awspring.cloud.autoconfigure.config.parameterstore.ParameterStoreReloadAutoConfiguration
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.awspring.cloud.autoconfigure.config.secretsmanager;

import io.awspring.cloud.autoconfigure.core.AwsAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.CredentialsProviderAutoConfiguration;
import io.awspring.cloud.autoconfigure.core.RegionProviderAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.mockito.internal.util.MockUtil;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

class SecretsManagerAutoConfigurationTests {

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(RegionProviderAutoConfiguration.class,
CredentialsProviderAutoConfiguration.class, SecretsManagerAutoConfiguration.class,
AwsAutoConfiguration.class));

@Test
void secretsManagerAutoConfigurationIsDisabled() {
this.contextRunner.withPropertyValues("spring.cloud.aws.secretsmanager.enabled:false")
.run(context -> assertThat(context).doesNotHaveBean(SecretsManagerClient.class));
}

@Test
void secretsManagerAutoConfigurationIsEnabled() {
this.contextRunner.withPropertyValues("spring.cloud.aws.secretsmanager.enabled:true")
.run(context -> assertThat(context).hasSingleBean(SecretsManagerClient.class));
}

@Test
void createsClientBeanByDefault() {
this.contextRunner
.run(context -> assertThat(context).hasSingleBean(SecretsManagerClient.class));
}

@Test
void usesCustomBeanWhenProvided() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(SecretsManagerClient.class);
assertThat(MockUtil.isMock(context.getBean(SecretsManagerClient.class))).isTrue();
});
}

@TestConfiguration
static class CustomConfiguration {

@Bean
SecretsManagerClient secretsManagerClient() {
return mock();
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.BootstrapRegistryInitializer;
import org.springframework.boot.SpringApplication;
Expand All @@ -44,6 +45,7 @@
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
Expand Down Expand Up @@ -97,12 +99,11 @@ void resolvesPropertyFromSecretsManager() {
SpringApplication application = new SpringApplication(App.class);
application.setWebApplicationType(WebApplicationType.NONE);

try (ConfigurableApplicationContext context = runApplication(application,
"aws-secretsmanager:/config/spring;/config/second")) {
assertThat(context.getEnvironment().getProperty("message")).isEqualTo("value from tests");
assertThat(context.getEnvironment().getProperty("another-parameter")).isEqualTo("another parameter value");
assertThat(context.getEnvironment().getProperty("secondMessage")).isEqualTo("second value from tests");
assertThat(context.getEnvironment().getProperty("non-existing-parameter")).isNull();
try (ConfigurableApplicationContext context = application.run("--spring.cloud.aws.secretsmanager.region=" + REGION,
"--spring.cloud.aws.secretsmanager.endpoint=" + localstack.getEndpoint(),
"--spring.cloud.aws.credentials.access-key=noop", "--spring.cloud.aws.credentials.secret-key=noop",
"--spring.cloud.aws.region.static=eu-west-1", "--logging.level.io.awspring.cloud.secretsmanager=debug")) {

}
}

Expand Down Expand Up @@ -479,6 +480,14 @@ private static void putSecretValue(LocalStackContainer localstack, String secret
@EnableAutoConfiguration
static class App {

@Bean
ApplicationRunner applicationRunner(SecretsManagerClient client) {
return args -> {
System.out.println(client.listSecrets().secretList());
System.out.println("FOOO!");
};
}

}

static class AwsConfigurerClientConfiguration implements BootstrapRegistryInitializer {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# importing single secret
spring.config.import: aws-secretsmanager:/secrets/spring-cloud-aws-sample-app
logging.level.io.awspring.cloud.secretsmanager: debug
#spring.config.import: aws-secretsmanager:/secrets/spring-cloud-aws-sample-app
logging.level:
io.awspring.cloud.secretsmanager: debug

# LocalStack configuration
spring.cloud.aws.endpoint: http://localhost:4566
Expand Down

0 comments on commit 1da30c4

Please sign in to comment.