Skip to content

Commit 1dc7a5f

Browse files
committed
Address review comments: disable by default and add docs
1 parent 80f17d7 commit 1dc7a5f

File tree

5 files changed

+168
-2
lines changed

5 files changed

+168
-2
lines changed

docs/modules/ROOT/pages/server/environment-repository.adoc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,36 @@ You can set `spring.cloud.config.server.accept-empty` to `false` so that Server
3939

4040
NOTE: You cannot place `spring.main.*` properties in a remote `EnvironmentRepository`. These properties are used as part of the application initialization.
4141

42+
== File Content Resolution
43+
44+
The Config Server can resolve the content of local files and serve them as Base64 encoded values.
45+
This is particularly useful for serving binary files, such as SSL keystores or certificates, within configuration properties.
46+
47+
To enable this feature, you must set the following property (it is disabled by default for security reasons):
48+
49+
[source,yaml]
50+
----
51+
spring:
52+
cloud:
53+
config:
54+
server:
55+
file-resolving:
56+
enabled: true
57+
----
58+
59+
WARNING: Enabling this feature allows the Config Server to read files from the local file system where the server is running. Ensure that the process has appropriate file system permissions and is running in a secure environment.
60+
61+
When this feature is enabled, you can use the `{file}` prefix in your configuration values followed by the path to the file.
62+
The Config Server will read the file, encode its content to a Base64 string, and replace the property value.
63+
64+
For example, in your backing repository (e.g., Git or Native), you can define a property like this:
65+
66+
[source,yaml]
67+
----
68+
server:
69+
ssl:
70+
key-store: {file}/etc/certs/keystore.jks
71+
key-password: my-secret-password
72+
----
73+
74+
In this example, the Config Server reads `/etc/certs/keystore.jks`, encodes it, and returns the Base64 string as the value of `server.ssl.key-store`.

spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/FileResolvingEnvironmentRepositoryConfiguration.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2024-2026 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+
117
package org.springframework.cloud.config.server.config;
218

319
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -22,7 +38,7 @@ public class FileResolvingEnvironmentRepositoryConfiguration {
2238
@Bean
2339
@Primary
2440
@ConditionalOnBean(EnvironmentRepository.class)
25-
@ConditionalOnProperty(value = "spring.cloud.config.server.file-resolving.enabled", matchIfMissing = true)
41+
@ConditionalOnProperty(value = "spring.cloud.config.server.file-resolving.enabled", havingValue = "true")
2642
public FileResolvingEnvironmentRepository fileResolvingEnvironmentRepository(EnvironmentRepository environmentRepository) {
2743
return new FileResolvingEnvironmentRepository(environmentRepository);
2844
}

spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/FileResolvingEnvironmentRepository.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2024-2026 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+
117
package org.springframework.cloud.config.server.environment;
218

319
import java.io.File;
@@ -7,6 +23,7 @@
723
import java.util.List;
824
import java.util.Map;
925
import java.util.Objects;
26+
1027
import org.apache.commons.logging.Log;
1128
import org.apache.commons.logging.LogFactory;
1229
import org.springframework.cloud.config.environment.Environment;
@@ -53,7 +70,8 @@ public Environment findOne(String application, String profile, String label) {
5370
String base64Content = readFileToBase64(filePath);
5471
modifiedMap.put(entry.getKey(), base64Content);
5572
modified = true;
56-
} catch (IOException e) {
73+
}
74+
catch (IOException e) {
5775
log.warn(String.format("Failed to resolve file content for property '%s'. path: %s", entry.getKey(), filePath), e);
5876
}
5977
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2024-2026 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.config.server.config;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.boot.autoconfigure.AutoConfigurations;
22+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
23+
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
24+
import org.springframework.cloud.config.server.environment.FileResolvingEnvironmentRepository;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.mockito.Mockito.mock;
30+
31+
/**
32+
* Tests for {@link FileResolvingEnvironmentRepositoryConfiguration}.
33+
*/
34+
class FileResolvingEnvironmentRepositoryConfigurationTests {
35+
36+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
37+
.withConfiguration(AutoConfigurations.of(FileResolvingEnvironmentRepositoryConfiguration.class));
38+
39+
@Test
40+
void shouldNotConfigureByDefault() {
41+
this.contextRunner
42+
.withUserConfiguration(MockRepositoryConfiguration.class)
43+
.run(context -> assertThat(context).doesNotHaveBean(FileResolvingEnvironmentRepository.class));
44+
}
45+
46+
@Test
47+
void shouldNotConfigureIfExplicitlyDisabled() {
48+
this.contextRunner
49+
.withUserConfiguration(MockRepositoryConfiguration.class)
50+
.withPropertyValues("spring.cloud.config.server.file-resolving.enabled=false")
51+
.run(context -> assertThat(context).doesNotHaveBean(FileResolvingEnvironmentRepository.class));
52+
}
53+
54+
@Test
55+
void shouldConfigureIfExplicitlyEnabled() {
56+
this.contextRunner
57+
.withUserConfiguration(MockRepositoryConfiguration.class)
58+
.withPropertyValues("spring.cloud.config.server.file-resolving.enabled=true")
59+
.run(context -> {
60+
assertThat(context).hasSingleBean(FileResolvingEnvironmentRepository.class);
61+
assertThat(context.getBean(EnvironmentRepository.class))
62+
.isInstanceOf(FileResolvingEnvironmentRepository.class);
63+
});
64+
}
65+
66+
@Test
67+
void shouldNotConfigureIfDelegateIsMissing() {
68+
this.contextRunner
69+
.withPropertyValues("spring.cloud.config.server.file-resolving.enabled=true")
70+
.run(context -> assertThat(context).doesNotHaveBean(FileResolvingEnvironmentRepository.class));
71+
}
72+
73+
@Configuration(proxyBeanMethods = false)
74+
static class MockRepositoryConfiguration {
75+
76+
@Bean
77+
EnvironmentRepository environmentRepository() {
78+
return mock(EnvironmentRepository.class);
79+
}
80+
81+
}
82+
83+
}

spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/FileResolvingEnvironmentRepositoryTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2024-2026 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+
117
package org.springframework.cloud.config.server.environment;
218

319
import java.io.File;

0 commit comments

Comments
 (0)