Skip to content
This repository was archived by the owner on Jan 19, 2022. It is now read-only.

Commit dfdc5c9

Browse files
committed
Add aws-secretsmanager: prefix config import
In `spring-boot` 2.4, `Volume Mounted Config Directory Trees` was added. This commit introduces the prefix `aws-secretsmanager:` which will resolve the values given the configuration properties supported by secrets manager integration. Also, if keys are added after the prefix then just these will be resolved. Use: `aws-secretsmanager:` or `aws-secretsmanager:my-secret-key` or `aws-secretsmanager:my-secret-key;my-anoter-secret-key` Closes gh-655
1 parent 5c17315 commit dfdc5c9

File tree

11 files changed

+464
-49
lines changed

11 files changed

+464
-49
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<parent>
2323
<groupId>org.springframework.cloud</groupId>
2424
<artifactId>spring-cloud-build</artifactId>
25-
<version>3.0.0-M4</version>
25+
<version>3.0.0-SNAPSHOT</version>
2626
<relativePath/><!-- lookup parent from repository -->
2727
</parent>
2828

@@ -48,7 +48,7 @@
4848
<javax-mail.version>1.5.5</javax-mail.version>
4949
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
5050
<javax.activation.version>1.2.0</javax.activation.version>
51-
<spring-cloud-commons.version>3.0.0-M4</spring-cloud-commons.version>
51+
<spring-cloud-commons.version>3.0.0-SNAPSHOT</spring-cloud-commons.version>
5252
<spring-javaformat.version>0.0.25</spring-javaformat.version>
5353
</properties>
5454

spring-cloud-aws-dependencies/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<parent>
2323
<groupId>org.springframework.cloud</groupId>
2424
<artifactId>spring-cloud-dependencies-parent</artifactId>
25-
<version>2.3.2.BUILD-SNAPSHOT</version>
25+
<version>3.0.0-SNAPSHOT</version>
2626
<relativePath/>
2727
</parent>
2828
<artifactId>spring-cloud-aws-dependencies</artifactId>

spring-cloud-aws-secrets-manager-config/src/main/java/org/springframework/cloud/aws/secretsmanager/AwsSecretsManagerPropertySourceLocator.java

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.springframework.core.env.ConfigurableEnvironment;
3232
import org.springframework.core.env.Environment;
3333
import org.springframework.core.env.PropertySource;
34-
import org.springframework.util.ReflectionUtils;
3534

3635
/**
3736
* Builds a {@link CompositePropertySource} with various
@@ -41,17 +40,18 @@
4140
*
4241
* @author Fabio Maia
4342
* @author Matej Nedic
43+
* @author Eddú Meléndez
4444
* @since 2.0.0
4545
*/
4646
public class AwsSecretsManagerPropertySourceLocator implements PropertySourceLocator {
4747

48-
private String propertySourceName;
48+
private final String propertySourceName;
4949

50-
private AWSSecretsManager smClient;
50+
private final AWSSecretsManager smClient;
5151

52-
private AwsSecretsManagerProperties properties;
52+
private final AwsSecretsManagerProperties properties;
5353

54-
private final Set<String> contexts = new LinkedHashSet();
54+
private final Set<String> contexts = new LinkedHashSet<>();
5555

5656
private Log logger = LogFactory.getLog(getClass());
5757

@@ -78,56 +78,20 @@ public PropertySource<?> locate(Environment environment) {
7878

7979
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
8080

81-
String appName = properties.getName();
82-
83-
if (appName == null) {
84-
appName = env.getProperty("spring.application.name");
85-
}
81+
AwsSecretsManagerPropertySources sources = new AwsSecretsManagerPropertySources(properties, logger);
8682

8783
List<String> profiles = Arrays.asList(env.getActiveProfiles());
88-
89-
String prefix = this.properties.getPrefix();
90-
91-
String appContext = prefix + "/" + appName;
92-
addProfiles(this.contexts, appContext, profiles);
93-
this.contexts.add(appContext);
94-
95-
String defaultContext = prefix + "/" + this.properties.getDefaultContext();
96-
addProfiles(this.contexts, defaultContext, profiles);
97-
this.contexts.add(defaultContext);
84+
this.contexts.addAll(sources.getAutomaticContexts(profiles));
9885

9986
CompositePropertySource composite = new CompositePropertySource(this.propertySourceName);
10087

10188
for (String propertySourceContext : this.contexts) {
102-
try {
103-
composite.addPropertySource(create(propertySourceContext));
104-
}
105-
catch (Exception e) {
106-
if (this.properties.isFailFast()) {
107-
logger.error(
108-
"Fail fast is set and there was an error reading configuration from AWS Secrets Manager:\n"
109-
+ e.getMessage());
110-
ReflectionUtils.rethrowRuntimeException(e);
111-
}
112-
else {
113-
logger.warn("Unable to load AWS secret from " + propertySourceContext, e);
114-
}
115-
}
89+
PropertySource<AWSSecretsManager> propertySource = sources.createPropertySource(propertySourceContext, true,
90+
this.smClient);
91+
composite.addPropertySource(propertySource);
11692
}
11793

11894
return composite;
11995
}
12096

121-
private AwsSecretsManagerPropertySource create(String context) {
122-
AwsSecretsManagerPropertySource propertySource = new AwsSecretsManagerPropertySource(context, this.smClient);
123-
propertySource.init();
124-
return propertySource;
125-
}
126-
127-
private void addProfiles(Set<String> contexts, String baseContext, List<String> profiles) {
128-
for (String profile : profiles) {
129-
contexts.add(baseContext + this.properties.getProfileSeparator() + profile);
130-
}
131-
}
132-
13397
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2013-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.aws.secretsmanager;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
23+
import org.apache.commons.logging.Log;
24+
25+
import org.springframework.util.StringUtils;
26+
27+
public class AwsSecretsManagerPropertySources {
28+
29+
private final AwsSecretsManagerProperties properties;
30+
31+
private final Log log;
32+
33+
public AwsSecretsManagerPropertySources(AwsSecretsManagerProperties properties, Log log) {
34+
this.properties = properties;
35+
this.log = log;
36+
}
37+
38+
public List<String> getAutomaticContexts(List<String> profiles) {
39+
List<String> contexts = new ArrayList<>();
40+
String prefix = this.properties.getPrefix();
41+
String defaultContext = getContext(prefix, this.properties.getDefaultContext());
42+
43+
String appName = this.properties.getName();
44+
45+
String appContext = prefix + "/" + appName;
46+
addProfiles(contexts, appContext, profiles);
47+
contexts.add(appContext);
48+
49+
addProfiles(contexts, defaultContext, profiles);
50+
contexts.add(defaultContext);
51+
return contexts;
52+
}
53+
54+
protected String getContext(String prefix, String context) {
55+
if (StringUtils.isEmpty(prefix)) {
56+
return context;
57+
}
58+
else {
59+
return prefix + "/" + context;
60+
}
61+
}
62+
63+
private void addProfiles(List<String> contexts, String baseContext, List<String> profiles) {
64+
for (String profile : profiles) {
65+
contexts.add(baseContext + this.properties.getProfileSeparator() + profile);
66+
}
67+
}
68+
69+
public AwsSecretsManagerPropertySource createPropertySource(String context, boolean optional,
70+
AWSSecretsManager client) {
71+
try {
72+
return new AwsSecretsManagerPropertySource(context, client);
73+
// TODO: howto call close when /refresh
74+
}
75+
catch (Exception e) {
76+
if (this.properties.isFailFast() || !optional) {
77+
throw new AwsSecretsManagerPropertySourceNotFoundException(e);
78+
}
79+
else {
80+
log.warn("Unable to load AWS secret from " + context, e);
81+
}
82+
}
83+
return null;
84+
}
85+
86+
static class AwsSecretsManagerPropertySourceNotFoundException extends RuntimeException {
87+
88+
AwsSecretsManagerPropertySourceNotFoundException(Exception source) {
89+
super(source);
90+
}
91+
92+
}
93+
94+
}

spring-cloud-starter-aws-secrets-manager-config/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
<groupId>org.springframework.cloud</groupId>
4545
<artifactId>spring-cloud-aws-secrets-manager-config</artifactId>
4646
</dependency>
47+
<dependency>
48+
<groupId>org.springframework.boot</groupId>
49+
<artifactId>spring-boot-starter-web</artifactId>
50+
</dependency>
4751
<dependency>
4852
<groupId>org.springframework.cloud</groupId>
4953
<artifactId>spring-cloud-aws-core</artifactId>

spring-cloud-starter-aws-secrets-manager-config/src/main/java/org/springframework/cloud/aws/autoconfigure/secretsmanager/AwsSecretsManagerBootstrapConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ AwsSecretsManagerPropertySourceLocator awsSecretsManagerPropertySourceLocator(AW
5555
@Bean
5656
@ConditionalOnMissingBean
5757
AWSSecretsManager smClient(AwsSecretsManagerProperties properties) {
58+
return createSecretsManagerClient(properties);
59+
}
60+
61+
public static AWSSecretsManager createSecretsManagerClient(AwsSecretsManagerProperties properties) {
5862
AWSSecretsManagerClientBuilder builder = AWSSecretsManagerClientBuilder.standard()
5963
.withClientConfiguration(SpringCloudClientConfiguration.getClientConfiguration());
6064
if (!StringUtils.isNullOrEmpty(properties.getRegion())) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2013-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.aws.autoconfigure.secretsmanager;
18+
19+
import java.util.Collections;
20+
21+
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
22+
23+
import org.springframework.boot.context.config.ConfigData;
24+
import org.springframework.boot.context.config.ConfigDataLoader;
25+
import org.springframework.boot.context.config.ConfigDataLoaderContext;
26+
import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
27+
import org.springframework.cloud.aws.secretsmanager.AwsSecretsManagerPropertySource;
28+
29+
/**
30+
* @author Eddú Meléndez
31+
* @since 2.3.0
32+
*/
33+
public class AwsSecretsManagerConfigDataLoader implements ConfigDataLoader<AwsSecretsManagerConfigDataResource> {
34+
35+
@Override
36+
public ConfigData load(ConfigDataLoaderContext context, AwsSecretsManagerConfigDataResource resource) {
37+
try {
38+
AWSSecretsManager ssm = context.getBootstrapContext().get(AWSSecretsManager.class);
39+
AwsSecretsManagerPropertySource propertySource = new AwsSecretsManagerPropertySource(resource.getContext(),
40+
ssm);
41+
return new ConfigData(Collections.singletonList(propertySource));
42+
}
43+
catch (Exception e) {
44+
throw new ConfigDataResourceNotFoundException(resource, e);
45+
}
46+
}
47+
48+
}

0 commit comments

Comments
 (0)