Problem statement: java.sql.SQLSyntaxErrorException: Could not connect to address=(host=127.0.0.1)(port=3306)(type=master) : (conn=1058) Access denied for user ''@'localhost' to database 'my-db' User is not available during startup.
Vault configuration:
vault write database/config/my-db \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" \
allowed_roles="healthy-role-r-wr" \
username="root" \
password="myrootpassword"
vault write database/roles/healthy-role-r-wr \
db_name=my-db \
creation_statements="CREATE USER '{{name}}'@'localhost' IDENTIFIED BY '{{password}}'; GRANT ALL PRIVILEGES ON my-db.* TO '{{name}}'@'localhost'; FLUSH PRIVILEGES;" \default_ttl="1h" \
max_ttl="24h"
I had to mention host @localhost without that I cannot connect to mysql while testing mysql command.
vault read database/creds/healthy-role-r-wr
Key Value
--- -----
lease_id database/creds/healthy-role-r-wr/DugI5aIeYPUg0lmjtcNSM87L
lease_duration 1h
lease_renewable true
password C1yN7Tl-00XlwkOwbFCh
username v_root_healthy-ro_7nl7RPTqb6QkAJ
mysql -uv_root_healthy-ro_7nl7RPTqb6QkAJ -pC1yN7Tl-00XlwkOwbFCh my-db
MariaDB [my-db]> select count(*) from my_table;
1 row in set (0.025 sec)
So seems Vault is rightly configured.
application.yml
spring:
application:
name: my-springboot-app
cloud:
vault:
host: 127.0.0.1
port: 8200
scheme: http
authentication: token
token: TOKEN
generic:
enabled: true
database:
backend: mysql
kv:
enabled: true
backend: tcds/kv/my-springboot-app
application-name: my-springboot-app
config:
import: vault://secret/my-springboot-app
datasource:
url: jdbc:mariadb://127.0.0.1:3306/my-db
driver-class-name: org.mariadb.jdbc.Driver
platform: mariadb
role: healthy-role-r-wr
#username: ${dbusername}
#password: ${dbpassword}
jpa:
show-sql: true
hibernate:
ddl-auto: update
POM:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
Dependancies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-vault-config-databases</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
In vault I have created a secret, essentially creating a KV with username and password as showed in application.yml above. If I pass this like:
#username: ${dbusername}
#password: ${dbpassword}
Then application start up cleanly and I can make API calls to get the user list. But this is not the way it suppose to be. As the username and password is being generated dynamically and must be used by application.
It seems I am missing some configuration since spring boot app can recognize the vault and it can communicate with it, just that it is not able to find the way to read the dynamic credentials.