2

In my Spring Boot project, I am trying to setup liquibase and use it between dev, test and production databases. Everything seems to be working fine, except passing credentials to liquibase.properties file from HashiCorp Vault. I am able to access credentials in application.properties without any issues, but I can't in liquibase.properties file. I have the following file and I would like pass URLs and credentials dynamically from password vault.

liquibase.properties

changeLogFile=src/main/resources/liquibase-changeLog.xml
url=jdbc:mysql://localhost:3306/oauth_reddit
username=tutorialuser
password=tutorialmy5ql
driver=com.mysql.jdbc.Driver
referenceUrl=hibernate:spring:org.baeldung.persistence.model
  ?dialect=org.hibernate.dialect.MySQLDialect
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml
spencergibb
  • 24,471
  • 6
  • 69
  • 75
Pavan Jadda
  • 4,306
  • 9
  • 47
  • 79

2 Answers2

1

liquibase.properties is used by liquibase directly. I'm not sure that spring is somehow modifying the liquibase.properties, it's probably used only by maven plugin. So you will need to create some additional parser in liquibase which is able to use Vault or just forget about liquibase.properties and use spring's properties.

bilak
  • 4,526
  • 3
  • 35
  • 75
  • I realized this after posting the question. For those who are looking for answers and found this post. `liquibase.properties` file would be used when migrating database changes using liquibase Maven plugin. But if you want to use `liquibase-hibernate5` dependency, just use `application.properties` file – Pavan Jadda Jun 24 '20 at 18:59
1

Below code fetches the db details from vault injects into data source, this datasource is used by liquibase to connect and execute the scripts

build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.4.4"
    id("io.spring.dependency-management") version "1.0.11.RELEASE"
    kotlin("jvm") version "1.4.31"
    kotlin("plugin.spring") version "1.4.31"
}

group = "com.db"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.cloud:spring-cloud-starter-bootstrap:3.0.2")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.liquibase:liquibase-core:4.3.2")
    implementation(files("libs/ojdbc6.jar"))
    implementation("org.springframework.cloud:spring-cloud-starter-vault-config:3.0.2")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "1.8"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

bootstrap.properties

spring.cloud.vault.application-name=database-config
spring.cloud.vault.token=XXXXX
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.host=localhost
spring.cloud.vault.port=8200

application.properties

logging.level.liquibase=DEBUG
spring.liquibase.change-log=classpath:db/changelog.xml
spring.liquibase.enabled=true

VaultDBConfig

import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("db")
class VaultDBConfig {
    var username: String? = null
    var password: String? = null
    var url: String? = null
}

DatabaseConfig

import oracle.jdbc.pool.OracleDataSource
import java.sql.SQLException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.Profile
import org.springframework.core.env.Environment
import javax.sql.DataSource

@Configuration
class DatabaseConfig(private val dbDetails: VaultDBConfig, private val environment: Environment) {

    val logger: Logger = LoggerFactory.getLogger(DatabaseConfig::class.java)

    @Primary
    @Bean
    @Throws(SQLException::class)
    fun dataSource(): DataSource? {
        val oracleDataSource = OracleDataSource()
        oracleDataSource.setURL(dbDetails.url)
        oracleDataSource.setUser(dbDetails.username)
        oracleDataSource.setPassword(dbDetails.password)
        return oracleDataSource
    }
}

Enable config properties in application.kt

@SpringBootApplication
@EnableConfigurationProperties(VaultDBConfig::class)
class ConfigApplication

fun main(args: Array<String>) {
    runApplication<ConfigApplication>(*args)
}

Vault insert

vault kv put secret/database-config db.username=xxx db.password=xxx dp.url=xxx