Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot - Key Store Password set in Code

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.

like image 472
Kenco Avatar asked Jul 07 '17 11:07

Kenco


2 Answers

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.

like image 103
Kenco Avatar answered Oct 18 '22 07:10

Kenco


  • spring boot:2.3.1.RELEASE
  • you need to add @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() {
        // ...
    }
}
like image 34
DaGuoAiHeLiangCha Avatar answered Oct 18 '22 08:10

DaGuoAiHeLiangCha