---
title: 'Configuración Spring Config Server'
---
Configuración del Spring Config Server
===
* **Coordinador Tecnológico:** Rafael Palau
* **Consultores:**
Julio Mello
Marcos Benítez
Marco Aquino
Ilse Grau
Lauro Segovia
Alan Sanier
# Contenido
[TOC]
# Introducción
En el documento se dará a conocer la utilización del *Spring Cloud Config* y la configuración necesaria para su funcionamiento.
# Objetivo
Configurar el servidor y el cliente del config server.
# Config Server
*Spring Cloud Config* es el enfoque cliente/servidor de Spring para almacenar y proveer configuraciones distribuidas en múltiples aplicaciones y entornos. Idealmente, este almacén de configuración está versionado bajo el control de versiones de Git y se puede modificar mientras se ejecuta la aplicación.
*Spring Cloud Config* permite exteriorizar y centralizar la configuración de los módulos en un solo lugar. Por defecto, utiliza un repositorio local en filesystem, pero también puede utilizar Git como repositorio para centralizar la configuración de cada uno de los servicios.

Figura 1. Esquema del Spring Cloud Config
# Configuración
En esta sección se presentan los pasos a seguir para configurar el proyecto servidor y cliente.
## Servidor
En servidor de configuración (spring config server) expone un conjunto de recursos para que los servicios (clientes) puedan acceder a sus configuraciones:
### Apis disponibles para obtención de configuraciones
```shell=
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
```
> El cliente que invoca al servicio del config server, agrega el valor de **application** utilizando el nombre configurado en la propiedad spring.application.name. de la misma.
> El valor de **profile** es el perfil activo asigando.
> El valor de **label** es una etiqueta de Git opcional.
Ejemplo de consulta vía HTTP:
```shell=
curl --location --request GET 'http://localhost:8888/usuarios-back/lsegovia' \
--header 'Authorization: Basic bWJlbXo6MTIzNDU='
```
## Prerrequisito
1. Crear el repositorio Git para almacenar los archivos de configuración.
Los archivos de configuración deben ser ordenados en directorios dentro del repositorio y el nombre del directorio debe coincidir con el *application.name* que fue declarado en el **application.properties** del consumidor.
Por ejemplo, en el caso de presupuesto, se tiene que crear un directorio **presupuesto** y dentro de este se deben crear los archivos de configuración.
Ejemplo:
```json=
-/tree/main/presupuesto/presupuesto-igrau.properties
```
2. Crear el repositorio Git para almacenar los archivos de configuración de usuarios y constraseñas que utilizarán el spring config server.
Cada linea que contenga el archivo de configuración de usuarios deber tener el siguiente formato
```json=
username:password
```
> El algoritmo de encriptación utilizado es el Bcrypt
3. Generación de token de acceso personal para el usuario del Gitlab
> [Ver: Run Spring config server](https://hackmd.io/1eb87bJ1RQyx7_SEsZStzw)
## Creación del proyecto
En primer lugar, se debe crear los dos proyectos Maven. El proyecto del servidor depende ¿del módulo **spring-cloud-config-server**, así como de los paquetes de inicio **spring-boot-starter-security** y **spring-boot-starter-web**:
```xml=
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
```
Para el proyecto *cliente* es necesarios agregar las siguientes dependencias :
```xml=
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
```
## Implementación del config server
La parte principal de la aplicación es una clase de configuración, más concretamente una **@SpringBootApplication**, que recoge toda la configuración necesaria a través de la anotación **@EnableConfigServer**:
Adicionalmente se agrega la anotación **EnableConfigurationProperties**, para la cargar los valores del archivo de configuración como una clase **Bean**
```java=
@EnableConfigServer
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
@EnableConfigurationProperties(value = { ConfigProperties.class })
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
//Método utilizado para precargar los registros de usuario
//los usuarios, los mismos son guardados en memoria en una base h2
//y son accedidos por el Spring Security para la validación de acceso a los
//recursos expuestos por el Spring config server
@Bean
@ConditionalOnProperty(prefix = "custom.config.server", name = "enabled", havingValue = "")
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
UsuarioDetallesServiceImpl service = ctx.getBean(UsuarioDetallesServiceImpl.class);
service.loadUsers();
};
}
}
```
### Creación de archivo de configuración
Para el correcto funcionamiento del Spring config server, es necesario agregar la configuración del puerto y la url al repositorio Gitlab, que proporciona nuestro contenido de configuraciones controlado por ramas.
También necesitamos establecer la configuración de un repositorio Git desde donde serán obtenidos los datos de usuarios que pueden acceder al server.
Ejemplo :
```json
server.port: ${PORT:8888}
spring.application.name=config-server
spring.cloud.config.server.git.uri= https://gitlab.siare.gov.py/siare-develop/spring-config-repo.git
spring.cloud.config.server.git.skipSsValidation=true
spring.cloud.config.server.git.username= configserver
spring.cloud.config.server.git.password={contraseña}
spring.cloud.config.server.git.default-label=main
spring.cloud.config.server.git.force-pull=true
spring.cloud.config.server.git.clone-on-start=true
spring.cloud.config.server.git.search-paths={application}
custom.config.server.url=https://gitlab.siare.gov.py/siare-develop/spring-config-server/-/raw/feature-add-spring-security/configuraciones/usuarios.pas
custom.config.server.token=
```
* Los datos importantes a cambiar de ser necesario son :
* uri : url del repositorio git donde estan todas las configuraciones por perfil de usuarios
* username : alias de usuario para el acceso del git
* password : contraseña asociada al usuario del git
* server.url : url del repositorio git donde se encuentra el listado de usuario y contraseña para el acceso al spring cloud server
* server.token : token de acceso asigando al usuario que tiene el **rol de Reporter** en el repositorio git, esto permite descargar el listado de usuarios y contraseñas del git
:::info
Observación : Estas configuraciones se pueden asignar en el momento de la ejecución del proyecto.
Los datos son de ejempl, es necasario cambiarlo.
:::
### Implementación del spring security
La implementación del spring security consta de los siguientes archivos principales
* SecurityConfig.java
El archivo es una clase de configuración para habilitar la funcionalidad del spring security.
En ella se configura el servicio de obtención de usuarios y el método de encriptación a ser utilizados por el **AuthenticationManager**. Así también la regla de filtros a utilizar para el acceso a recursos expuestos.
```java=
@Configuration
@EnableWebSecurity
@AllArgsConstructor
@ConditionalOnProperty(prefix = "custom.config.server", name = "enabled", havingValue = "")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetails;
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable().csrf().disable()
.addFilterAt(new AuthCustomFilter(authenticationManager()), BasicAuthenticationFilter.class)
.authorizeRequests().mvcMatchers("/**").authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails).passwordEncoder(passwordEncoder);
}
}
```
* AuthCustomFilter.java
El archivo es una clase que hereda comportamientos del Filtro *OncePerRequestFilter*, que permite interceptar las peticiones HTTP entrantes y tratarlos.
En ella se verifica la existencia de usuario y contraseña en la cabecera HTTP de la petición realizada y delega la verificación del mismo al **AuthenticationManager**.
```java=
public class AuthCustomFilter extends OncePerRequestFilter {
private AuthenticationManager authenticationManager;
public AuthCustomFilter(AuthenticationManager authenticationManager) {
super();
this.authenticationManager = authenticationManager;
}
private BasicAuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
UsernamePasswordAuthenticationToken authRequest = this.authenticationConverter.convert(request);
if (authRequest == null) {
this.logger.trace("Did not process authentication request since failed to find "
+ "username and password in Basic Authorization header");
filterChain.doFilter(request, response);
return;
}
String username = authRequest.getName();
Object password = authRequest.getCredentials();
if (Objects.nonNull(username) && Objects.nonNull(password)) {
Authentication authResult = this.authenticationManager.authenticate(authRequest);
if (authResult.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authResult);
filterChain.doFilter(request, response);
} else {
this.logger.debug("Did not process authentication request since failed to find "
+ "username and password in Basic Authorization header");
filterChain.doFilter(request, response);
return;
}
}
} catch (AuthenticationException ex) {
SecurityContextHolder.clearContext();
this.logger.debug("Failed to process authentication request", ex);
return;
}
filterChain.doFilter(request, response);
}
}
```
* ConfigServer.java
El archivo es una clase de configuración para la creación del tipo de encriptación a ser utilizado por el **AuthenticationManager**.
```java=
@Configuration
public class ConfigServer {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
## Implementación del config server client
Para poder consumir los servicios expuestos por el config server es necesario realizar las siguientes configuraciones :
1. Agregar al pom.xml del proyecto consumidor:
> 1.1. Dependencia con el spring-cloud-starter-config y spring-boot-starter-web:
```xml=
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
```
> 1.2. versión de spring-cloud en properties:
```xml=
<properties>
...
<spring-cloud.version>2020.0.4</spring-cloud.version>
</properties>
```
> 1.3. manejo de las depencencias de spring cloud
```xml=
<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>
```
> 1.4 Goals de ejecución para el plugin de spring-boot
```xml
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
<configuration>
.....
</configuration>
</plugin>
```
2. Agregar en el archivo **application.properties** de la aplicación cliente creada las configuraciones necesarias para la conexión con el *spring cloud config server*.
Ejemplo de configuración:
```json
# Application Name
spring.application.name=presupuesto
# Spring Cloud Config Server Repository
spring.config.import=configserver:http://db-dev.siare.gov.py:8888/
spring.cloud.config.uri= http://db-dev.siare.gov.py:8888/
spring.cloud.config.fail-fast=true
spring.profiles.active=local
spring.cloud.config.username=dev
spring.cloud.config.password=12345
```
3. Configurar el despliegue en entorno local agregando el nombre del perfil correspondiente (Ver Figura 2 y 3).

Figura 2. Despliegue

Figura 3. Configuración
> En caso que el despliegue falle, primero es necesario ejecutar la operación de *maven install* antes de volver a desplegar la aplicación.
* Otra forma de ejecutar el proyecto es desde la terminal de comandos, situarse en la carpeta ...\siare-back\presupuesto del proyecto y ejecutar la instrucción
```shell=
java -server -jar /target/presupuesto-1.0.3.jar --spring.profile.active=<nombre perfil>
```
# Recursos
* [using-spring-config-server](https://dzone.com/articles/using-spring-config-server)
* [Generador de contraseñas utilizando Bcrypt](https://bcrypt-generator.com/).
* [Formato del archivo de usuarios y contraseñas](https://httpd.apache.org/docs/2.4/programs/htpasswd.html)
* [Configuración del archivo .properties](https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html)