Spring Boot Version: 1.5.4.RELEASE
I'm currently having an issue with setting my server.ssl.key-store-password
within the code of my Spring Boot application. We store our passwords in a vault, and I was previously passing it in via a -D
property. This, however, isn't an ideal solution for us.
The solution seemed simple, and below is what I did:
@Bean
public ServletContextInitializer initializer() {
final String keyStorePassword;
// ... Get Password
return servletContext -> servletContext.setInitParameter("server.ssl.key-store-password", keyStorePassword);
}
According to the Spring Boot Documentation this should be fine, as the ServletConfig
is loaded before the application.properties
.
Unfortunately, Tomcat refuses to start with the server.ssl.key-store-password
set in this way. From what I can see, the AbstractNestablePropertyAccessor
constructs an org.springframework.boot.context.embedded.Ssl
object which is fed to Tomcat, and used to construct the keystore. This is done during SpringApplication.run()
, which is obviously prior to construction of the ServletConfig
bean.
So it seems that I need to 'refresh' the context (which from what I understand is destroying/recreating it), or find another approach. I could set the property using something like:
public static void main(String[] args) {
String keyStorePassword = getKeystorePassword();
HashMap<String, Object> props = new HashMap<>();
props.put("server.ssl.key-store-password", keyStorePassword);
new SpringApplicationBuilder()
.sources(TesterApplication.class)
.properties(props)
.run(args);
}
This has its own problems though. I was thinking of storing the 'label' for the vault password in my application.yml, but if I do so, then I don't have access to that label before Spring has started (without manually parsing the application.yml, which poses its own problems with multiple profiles).
Has anyone else encountered a solution to this issue? Perhaps my approach is wrong, and there's a simpler way of doing things.
Right, figured it out. Was on the wrong track. What I should have done was the following:
@Component
public class KeystoreInit {
private final Environment environment;
@Autowired
public KeystoreInit(Environment environment) {
this.environment = environment;
}
@Bean
public ServerProperties serverProperties() {
final ServerProperties serverProperties = new ServerProperties();
final Ssl ssl = new Ssl();
final String keystorePassword = getKeystorePassword();
ssl.setKeyPassword(keystorePassword);
System.setProperty("server.ssl.key-store-password", keystorePassword);
serverProperties.setSsl(ssl);
return serverProperties;
}
private String getKeystorePassword() {
// ...
}
}
The idea here is that we're creating the initial ServerProperties
bean. This bean is then loaded instead of a fresh ServerProperties
, so our Ssl
with the keystore password is set there already. This isn't overridden since we don't set server.ssl.key-store-password
in our application.yml
.
We @Autowire
the Environment
so that we can access out server.ssl.key-store-label
property (which I had previously created), use that to load our actual server.ssl.key-store-password
property, and then set that via System properties so that it can be accessed elsewhere in the application.
@Primary
at method otherwise it will Start error.What I should have done was the following:@Component
public class KeystoreInit {
private final Environment environment;
@Autowired
public KeystoreInit(Environment environment) {
this.environment = environment;
}
@Bean
@Primary
public ServerProperties serverProperties() {
final ServerProperties serverProperties = new ServerProperties();
final Ssl ssl = new Ssl();
final String keystorePassword = getKeystorePassword();
ssl.setKeyPassword(keystorePassword);
System.setProperty("server.ssl.key-store-password", keystorePassword);
serverProperties.setSsl(ssl);
return serverProperties;
}
private String getKeystorePassword() {
// ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With