Declaración del problema:
java.sql.SQLSyntaxErrorException: No se pudo conectar a la dirección = (host = 127.0.0.1) (puerto = 3306) (tipo = maestro): (conn = 1058) Acceso denegado para el usuario ''@'localhost' a la base de datos 'my- db'
El usuario no está disponible durante el inicio.
Configuración de la bóveda:
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"
Tuve que mencionar el host @localhost sin eso no puedo conectarme a mysql mientras pruebo el comando mysql.
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)
Parece que Vault está configurado correctamente.
aplicación.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>
Dependencias:
<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>
En Vault he creado un secreto, esencialmente creando un KV con nombre de usuario y contraseña como se muestra en application.yml arriba. Si paso esto como:
#username: ${dbusername}
#password: ${dbpassword}
Entonces la aplicación se inicia limpiamente y puedo realizar llamadas API para obtener la lista de usuarios. Pero este no es el camino.Y se supone que es así. Dado que el nombre de usuario y la contraseña se generan dinámicamente y la aplicación debe utilizarlos.
Parece que me falta alguna configuración ya que la aplicación Spring Boot puede reconocer la bóveda y comunicarse con ella, solo que no puede encontrar la manera de leer las credenciales dinámicas.
Acceso denegado al usuario ''@'localhost' indica que recurre al usuario anónimo en lugar de a la autenticación proporcionada.
- danblack
28 de marzo de 2021 a las 5:53
------------------------------------
Su problema suena similar en muchos aspectos al que encontré y en el que he estado trabajando durante unos días, así que lo publicaré aquí en caso de que le ayude a usted o a alguien más.
Si está almacenando el nombre de usuario y/o la contraseña en su kv con nombres de propiedad que coinciden con lo que el complemento de la base de datos cargará dinámicamente, habrá cargadores de propiedades duplicados con la misma clave y los valores de kv tomarán precedencia.
Por ejemplo en mi caso lo había hecho
vault kv put secret/foo spring.datasource.password=wrongpassword
(la clave predeterminada para la contraseña utilizada por el complemento DB para cargar la contraseña es spring.datasource.password)
Mientras pueda llamar
vault read database/creds/some-role
y obtener credenciales válidas cuando ejecuté mi SpAplicación ringBoot Descubrí que la contraseña utilizada era el valor kv. Al depurar, vi que esto se debía a la precedencia del cargador de propiedades.
Si borra su kv de cualquier par clave/valor que usaría el complemento de base de datos, debería usar las credenciales dinámicas generadas por el rol que definió.
Además, tengo entendido que para configurar la fuente de datos necesitaría un archivo bootstrap.yml que contendría la información de su bóveda para modificar el comportamiento de inicio de la aplicación SpringBoot.
spring:
application:
name: <app name>
cloud:
vault:
database:
enabled: true
role: <role>
backend: database
host: <host>
port: <port>
scheme: https
authentication: token
token: <your vault token>
uri: <vault URL>
Esta otra respuesta también me resultó útil. Me permitió ver los valores de propiedad de mi aplicación Spring Cloud - bootstrap.properties fuera de mi jar
------------------------------------
El rol que creó debe aparecer en spring.cloud.vault.database como se muestra a continuación
database:
enabled: true
role: healthy-role-r-wr
backend: database # not mysql as you have it in your config
He creado un vídeo sobre esto en detalle si quieres profundizar en ello.