Pr 2104 polish (#2233)

* Support labels in AWS SecretsManager backend

* Document label support in AWS SecretsManager

* Use AWS staged labels as config version labels

* Fix tests

---------

Co-authored-by: Dmitry Antonyuk <32649457+dantonyuk@users.noreply.github.com>
Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
This commit is contained in:
Ryan Baxter
2023-02-23 10:16:01 -05:00
committed by GitHub
parent 8d11dbdf8e
commit 8b7ebf944c
4 changed files with 1843 additions and 84 deletions

View File

@@ -866,7 +866,54 @@ secret value =
}
----
===== AWS Parameter Store
===== Labelled Versions
AWS Secrets Manager repository allows to keep labelled versions of the configuration environments the same way Git backend does.
The repository implementation maps the `{label}` parameter of the HTTP resource to https://docs.aws.amazon.com/secretsmanager/latest/userguide/getting-started.html#term_version[AWS Secrets Manager secret's staging label^]. To create a labelled secret, create a secret or update its content and define a staging label for it (sometimes it's called version stage in the AWS documentation). For example:
[source,sh]
----
$ aws secretsmanager create-secret \
--name /secret/test/ \
--secret-string '{"version":"1"}'
{
"ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:/secret/test/-a1b2c3",
"Name": "/secret/test/",
"VersionId": "cd291674-de2f-41de-8f3b-37dbf4880d69"
}
$ aws secretsmanager update-secret-version-stage \
--secret-id /secret/test/ \
--version-stage 1.0.0 \
--move-to-version-id cd291674-de2f-41de-8f3b-37dbf4880d69
{
"ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:/secret/test/-a1b2c3",
"Name": "/secret/test/",
}
----
Use `spring.cloud.config.server.aws-secretsmanager.default-label` property to set the default label. If the property is not defined, the backend uses AWSCURRENT as a staging label.
[source,yaml]
----
spring:
profiles:
active: aws-secretsmanager
cloud:
config:
server:
aws-secretsmanager:
region: us-east-1
default-label: 1.0.0
----
Note that if the default label is not set and a request does not define a label, the repository will use secrets as if labelled version support is disabled. Also, the default label will be used only if the labelled support is enabled. Otherwise, defining this property is pointless.
Note that if the staging label contains a slash (`/`), then the label in the HTTP URL should instead be specified with the special string `({special-string})` (to avoid ambiguity with other URL paths) the same way <<_git_backend,Git backend's section>> describes it.
==== AWS Parameter Store
When using AWS Parameter Store as a backend, you can share configuration with all applications by placing properties within the `/application` hierarchy.

View File

@@ -48,6 +48,12 @@ public class AwsSecretsManagerEnvironmentProperties implements EnvironmentReposi
*/
private String endpoint;
/**
* The default staging label to be used to fetch the secret values. If unset, an
* active version of the secret will be fetched (AWSCURRENT).
*/
private String defaultLabel;
/**
* The order of the environment repository.
*/
@@ -91,6 +97,14 @@ public class AwsSecretsManagerEnvironmentProperties implements EnvironmentReposi
this.endpoint = endpoint;
}
public String getDefaultLabel() {
return defaultLabel;
}
public void setDefaultLabel(String defaultLabel) {
this.defaultLabel = defaultLabel;
}
public int getOrder() {
return order;
}

View File

@@ -71,6 +71,7 @@ public class AwsSecretsManagerEnvironmentRepository implements EnvironmentReposi
public Environment findOne(String application, String profileList, String label) {
final String defaultApplication = configServerProperties.getDefaultApplicationName();
final String defaultProfile = configServerProperties.getDefaultProfile();
final String defaultLabel = environmentProperties.getDefaultLabel();
if (ObjectUtils.isEmpty(application)) {
application = defaultApplication;
@@ -80,6 +81,10 @@ public class AwsSecretsManagerEnvironmentRepository implements EnvironmentReposi
profileList = defaultProfile;
}
if (StringUtils.isEmpty(label)) {
label = defaultLabel;
}
String[] profiles = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(profileList));
Environment environment = new Environment(application, profiles, label, null, null);
@@ -89,33 +94,33 @@ public class AwsSecretsManagerEnvironmentRepository implements EnvironmentReposi
}
for (String profile : profiles) {
addPropertySource(environment, application, profile);
addPropertySource(environment, application, profile, label);
if (!defaultApplication.equals(application)) {
addPropertySource(environment, defaultApplication, profile);
addPropertySource(environment, defaultApplication, profile, label);
}
}
if (!Arrays.asList(profiles).contains(defaultProfile)) {
addPropertySource(environment, application, defaultProfile);
addPropertySource(environment, application, defaultProfile, label);
}
if (!Arrays.asList(profiles).contains(defaultProfile) && !defaultApplication.equals(application)) {
addPropertySource(environment, defaultApplication, defaultProfile);
addPropertySource(environment, defaultApplication, defaultProfile, label);
}
if (!defaultApplication.equals(application)) {
addPropertySource(environment, application, null);
addPropertySource(environment, application, null, label);
}
addPropertySource(environment, defaultApplication, null);
addPropertySource(environment, defaultApplication, null, label);
return environment;
}
private void addPropertySource(Environment environment, String application, String profile) {
private void addPropertySource(Environment environment, String application, String profile, String label) {
String path = buildPath(application, profile);
Map<Object, Object> properties = findProperties(path);
Map<Object, Object> properties = findProperties(path, label);
if (!properties.isEmpty()) {
environment.add(new PropertySource(environmentProperties.getOrigin() + path, properties));
}
@@ -133,10 +138,10 @@ public class AwsSecretsManagerEnvironmentRepository implements EnvironmentReposi
}
}
private Map<Object, Object> findProperties(String path) {
private Map<Object, Object> findProperties(String path, String label) {
Map<Object, Object> properties = new HashMap<>();
GetSecretValueRequest request = GetSecretValueRequest.builder().secretId(path).build();
GetSecretValueRequest request = GetSecretValueRequest.builder().secretId(path).versionStage(label).build();
try {
GetSecretValueResponse response = awsSmClient.getSecretValue(request);