mysql: las credenciales de nombre de usuario de la bóveda MariaDB de Spring Boot no están disponibles durante el inicio

CorePress2024-01-25  10

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.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare