Using alternative credentials for Liquibase in Spring Boot

One of the projects I’m working uses Spring Boot to handle all database changes for each micro-service. One of the obvious requirements to make this work is a database user with DBA rights, otherwise it can not create, alter or drop tables.

You could configure the default datasource to use such user, but this would mean that every component will use this datasource and in case of a security breach (eg. SQL injection) this would be bad because all of a sudden someone else has DBA access to your database.

Therefore it’s best to configure a second datasource for Liquibase with a DBA user and a primary datasource with a read-write database user.

Configuring the Liquibase datasource

	@LiquibaseDataSource
	@Bean
	public DataSource liquibaseDataSource() {
		DataSource ds =  DataSourceBuilder.create()
				.username(liquibaseDataSourceProperties.getUser())
				.password(liquibaseDataSourceProperties.getPassword())
				.url(liquibaseDataSourceProperties.getUrl())
				.driverClassName(liquibaseDataSourceProperties.getDriver())
				.build();
		if (ds instanceof org.apache.tomcat.jdbc.pool.DataSource) {
			((org.apache.tomcat.jdbc.pool.DataSource) ds).setInitialSize(0);
			((org.apache.tomcat.jdbc.pool.DataSource) ds).setMaxActive(2);
			((org.apache.tomcat.jdbc.pool.DataSource) ds).setMaxAge(30000);
			((org.apache.tomcat.jdbc.pool.DataSource) ds).setMinIdle(0);
			((org.apache.tomcat.jdbc.pool.DataSource) ds).setMinEvictableIdleTimeMillis(60000);
		} else {
			LOG.warn("#################################################################");
			LOG.warn("Datasource was not of type org.apache.tomcat.jdbc.pool.DataSource");
			LOG.warn("but was of type {}", ds.getClass().getName());
			LOG.warn("Number of leaked connections might be 10 per instance !");
			LOG.warn("#################################################################");
		}

		LOG.info("Initialized a datasource for {}", liquibaseDataSourceProperties.getUrl());
		return ds;
	}

FYI: LiquibaseDataSourceProperties is just a standard bean annotated with

@Component
@ConfigurationProperties("datasource.liquibase")

in order to have different configurations per environment. Just must configure the pool to only use one connection and to release this connection after a while, otherwise your user will keep 10 connections open. With 10 micro-services which can be up- and down-scaled you’ll quickly block over 100 database connections which might prevent your application to make new connections. In our case Spring uses the default Tomcat pool as it’s readily available on the classpath, but it might be different for your setup.
For more info see the original Stackoverflow question.

Configuring the default datasource

If you already have a datasource configured in your application then you just need to annotate it with  the @Primary annotation to make sure that this read-write user is the one used by all the other Spring components. If you don’t do this then Spring Boot won’t start because you have 2 instances of DataSource configured and Spring doesn’t know which one to pick.

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s