From 4c60e9f0b1432337496e5b2eb41627ec76d0b450 Mon Sep 17 00:00:00 2001 From: matejnedic Date: Sun, 14 Dec 2025 10:21:48 +0100 Subject: [PATCH] #1535-log-secrets-manager-failures-key-not-found --- ...anagerPropertySourceNotFoundException.java | 24 ++++++++++++++ .../SecretsManagerConfigDataLoader.java | 32 ++++++++----------- ...cretsManagerExceptionHappenedAnalyzer.java | 13 ++++++++ .../SecretsManagerPropertySources.java | 8 ----- .../main/resources/META-INF/spring.factories | 1 + ...nagerConfigDataLoaderIntegrationTests.java | 19 +++++++++++ 6 files changed, 70 insertions(+), 27 deletions(-) create mode 100644 spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/AwsSecretsManagerPropertySourceNotFoundException.java create mode 100644 spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerExceptionHappenedAnalyzer.java diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/AwsSecretsManagerPropertySourceNotFoundException.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/AwsSecretsManagerPropertySourceNotFoundException.java new file mode 100644 index 0000000000..5b54ee7fc3 --- /dev/null +++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/AwsSecretsManagerPropertySourceNotFoundException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2013-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.awspring.cloud.autoconfigure.config.secretsmanager; + +public class AwsSecretsManagerPropertySourceNotFoundException extends RuntimeException { + + AwsSecretsManagerPropertySourceNotFoundException(Exception source) { + super(source); + } + +} diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoader.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoader.java index 2b5e1a39a1..8189d8f41f 100644 --- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoader.java +++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoader.java @@ -22,7 +22,6 @@ import org.springframework.boot.context.config.ConfigData; import org.springframework.boot.context.config.ConfigDataLoader; import org.springframework.boot.context.config.ConfigDataLoaderContext; -import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.core.env.MapPropertySource; import org.springframework.lang.Nullable; @@ -47,28 +46,23 @@ public SecretsManagerConfigDataLoader(DeferredLogFactory logFactory) { @Override @Nullable public ConfigData load(ConfigDataLoaderContext context, SecretsManagerConfigDataResource resource) { - try { - // resource is disabled if secrets manager integration is disabled via - // spring.cloud.aws.secretsmanager.enabled=false - if (resource.isEnabled()) { - SecretsManagerClient sm = context.getBootstrapContext().get(SecretsManagerClient.class); - SecretsManagerPropertySource propertySource = resource.getPropertySources() - .createPropertySource(resource.getContext(), resource.isOptional(), sm); - if (propertySource != null) { - return new ConfigData(Collections.singletonList(propertySource)); - } - else { - return null; - } + // resource is disabled if secrets manager integration is disabled via + // spring.cloud.aws.secretsmanager.enabled=false + if (resource.isEnabled()) { + SecretsManagerClient sm = context.getBootstrapContext().get(SecretsManagerClient.class); + SecretsManagerPropertySource propertySource = resource.getPropertySources() + .createPropertySource(resource.getContext(), resource.isOptional(), sm); + if (propertySource != null) { + return new ConfigData(Collections.singletonList(propertySource)); } else { - // create dummy empty config data - return new ConfigData( - Collections.singletonList(new MapPropertySource("aws-secretsmanager:" + context, Map.of()))); + return null; } } - catch (Exception e) { - throw new ConfigDataResourceNotFoundException(resource, e); + else { + // create dummy empty config data + return new ConfigData( + Collections.singletonList(new MapPropertySource("aws-secretsmanager:" + context, Map.of()))); } } diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerExceptionHappenedAnalyzer.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerExceptionHappenedAnalyzer.java new file mode 100644 index 0000000000..23a7b55ba1 --- /dev/null +++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerExceptionHappenedAnalyzer.java @@ -0,0 +1,13 @@ +package io.awspring.cloud.autoconfigure.config.secretsmanager; + +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +public class SecretsManagerExceptionHappenedAnalyzer extends AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, AwsSecretsManagerPropertySourceNotFoundException cause) { + return new FailureAnalysis("Could not import properties from AWS Secrets Manager. Exception happened while trying to load the keys: " + cause.getMessage(), + "Depending on error message determine action course", cause); + } +} diff --git a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerPropertySources.java b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerPropertySources.java index a724cc4e5d..41b1d96899 100644 --- a/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerPropertySources.java +++ b/spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerPropertySources.java @@ -61,12 +61,4 @@ public SecretsManagerPropertySource createPropertySource(String context, boolean return null; } - static class AwsSecretsManagerPropertySourceNotFoundException extends RuntimeException { - - AwsSecretsManagerPropertySourceNotFoundException(Exception source) { - super(source); - } - - } - } diff --git a/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories index 6dd5278a98..2c51180965 100644 --- a/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-aws-autoconfigure/src/main/resources/META-INF/spring.factories @@ -13,6 +13,7 @@ io.awspring.cloud.autoconfigure.config.s3.S3ConfigDataLoader # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ io.awspring.cloud.autoconfigure.config.parameterstore.ParameterStoreMissingKeysFailureAnalyzer, \ +io.awspring.cloud.autoconfigure.config.secretsmanager.SecretsManagerExceptionHappenedAnalyzer, \ io.awspring.cloud.autoconfigure.config.parameterstore.ParameterStoreExceptionHappenedAnalyzer, \ io.awspring.cloud.autoconfigure.config.secretsmanager.SecretsManagerMissingKeysFailureAnalyzer,\ io.awspring.cloud.autoconfigure.config.s3.S3MissingKeysFailureAnalyzer diff --git a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoaderIntegrationTests.java b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoaderIntegrationTests.java index b92a143258..6ec4f2a09f 100644 --- a/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoaderIntegrationTests.java +++ b/spring-cloud-aws-autoconfigure/src/test/java/io/awspring/cloud/autoconfigure/config/secretsmanager/SecretsManagerConfigDataLoaderIntegrationTests.java @@ -211,6 +211,25 @@ void whenKeysAreNotSpecifiedFailsWithHumanReadableFailureMessage(CapturedOutput } } + @Test + void whenKeysCannotBeFoundFailWithHumanReadableMessage(CapturedOutput output) { + SpringApplication application = new SpringApplication(App.class); + application.setWebApplicationType(WebApplicationType.NONE); + + try (ConfigurableApplicationContext context = runApplication(application, "aws-secretsmanager:/some/random/config")) { + fail("Context without keys should fail to start"); + } + catch (Exception e) { + assertThat(e).isInstanceOf(AwsSecretsManagerPropertySourceNotFoundException.class); + // ensure that failure analyzer catches the exception and provides meaningful + // error message + // Ensure that new line character should be platform independent + String errorMessage = "Description:%1$s%1$sCould not import properties from AWS Secrets Manager. Exception happened while trying to load" + .formatted(NEW_LINE_CHAR); + assertThat(output.getOut()).contains(errorMessage); + } + } + @Test void secretsManagerClientCanBeOverwrittenInBootstrapConfig() { SecretsManagerClient mockClient = mock(SecretsManagerClient.class);