Introduction rapide à la configuration Spring Cloud

1. Vue d’ensemble

  • Spring Cloud Config ** est l’approche client/serveur de Spring pour stocker et servir des configurations distribuées dans plusieurs applications et environnements.

Ce magasin de configuration est idéalement versionné sous le contrôle de version Git et peut être modifié au moment de l’exécution de l’application. Bien qu’il s’intègre très bien dans les applications Spring utilisant tous les formats de fichier de configuration pris en charge ainsi que des constructions telles que Environment , PropertySource ou @Value , il peut être utilisé dans tout environnement exécutant un langage de programmation.

Dans cet article, nous allons nous concentrer sur un exemple de configuration d’un serveur de configuration sauvegardé par Git , de l’utiliser dans un simple serveur d’application REST et de configurer un environnement sécurisé comprenant des valeurs de propriété chiffrées.

2. Configuration du projet et dépendances

Pour nous préparer à écrire du code, nous créons d’abord deux nouveaux projets Maven . Le projet de serveur s’appuie sur les https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-config- serveur% 22[spring-cloud-config-server] , ainsi que le module https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.boot%22% 20AND% 20a% 3A% 22spring-boot-starter-security% 22[spring-boot-starter-security] et https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org .springframework.boot% 22% 20and% 20a% 3A% 22spring-boot-starter-web% 22[ensembles de démarrage à ressort] kits de démarrage:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>1.4.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.4.0.RELEASE</version>
</dependency>

Cependant, pour le projet client, nous n’aurons besoin que de https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A% 22spring-cloud-starter-config% 22[printemps-cloud-starter-config] et le https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.boot% 22% 20AND% 20a% 3A% 22Spring-Boot-Starter-Web% 22[modules Spring-Boot-Starter-Web] :

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.4.0.RELEASE</version>
</dependency>

3. Une implémentation du serveur de configuration

La partie principale de l’application est une classe de configuration - plus spécifiquement un lien:/spring-boot-application-configuration[ @ SpringBootApplication ]- qui récupère toute la configuration requise via l’annotation auto-configure EnableConfigServer: __

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {

    public static void main(String[]arguments) {
        SpringApplication.run(ConfigServer.class, arguments);
    }
}

Maintenant, nous devons configurer le serveur port sur lequel notre serveur est à l’écoute et un Git -url qui fournit le contenu de notre configuration contrôlée par la version. Ce dernier peut être utilisé avec des protocoles tels que http , ssh ou un simple fichier__fichier sur un système de fichiers local.

  • Conseil: ** Si vous envisagez d’utiliser plusieurs instances de serveur de configuration pointant vers le même référentiel de configuration, vous pouvez configurer le serveur pour cloner votre référentiel dans un dossier temporaire local. Mais sachez que les référentiels privés avec authentification à deux facteurs sont difficiles à manipuler! Dans un tel cas, il est plus facile de les cloner sur votre système de fichiers local et de travailler avec la copie.

Il y a aussi quelques variables de lieu de détention et modèles de recherche pour configurer le repository-url__ disponible; mais cela sort du cadre de notre article. Si vous êtes intéressé, la documentation officielle est un bon point de départ.

Nous devons également définir un nom d’utilisateur et un mot de passe pour Basic-Authentication dans notre application.properties afin d’éviter un mot de passe généré automatiquement à chaque redémarrage de l’application:

server.port=8888
spring.cloud.config.server.git.uri=ssh://localhost/config-repo
spring.cloud.config.server.git.clone-on-start=true
security.user.name=root
security.user.password=s3cr3t

4. Un référentiel Git en tant que stockage de configuration

Pour compléter notre serveur, nous devons initialiser un référentiel Git sous l’URL configurée, créer de nouveaux fichiers de propriétés et les vulgariser avec certaines valeurs.

Le nom du fichier de configuration est composé comme un Spring application.properties normal, mais au lieu du mot "application", un nom configuré, par exemple la valeur de la propriété ’spring.application.name ’ du client est utilisée, suivie d’un tiret et du profil actif. Par exemple:

$> git init
$> echo 'user.role=Developer' > config-client-development.properties
$> echo 'user.role=User'      > config-client-production.properties
$> git add .
$> git commit -m 'Initial config-client properties'
  • Dépannage: ** Si vous rencontrez des problèmes d’authentification liés à ssh , revérifiez ~/.ssh/known hosts et ~/.ssh/registered keys sur votre serveur ssh!

5. Interrogation de la configuration

Nous sommes maintenant en mesure de démarrer notre serveur. L’API de configuration soutenue par Git fourni par notre serveur peut être interrogé à l’aide des chemins suivants:

----/{application}/{profile}[/{label}]/{application}-{profile}.yml/{label}/{application}-{profile}.yml/{application}-{profile}.properties/{label}/{application}-{profile}.properties
----

Dans lequel l’espace réservé \ {{label} fait référence à une branche Git, \ {{application} au nom de l’application du client et le \ {profil} au profil de l’application active actuelle du client.

Nous pouvons donc récupérer la configuration de notre client de configuration planifié fonctionnant sous un profil de développement dans la branche master via:

$> curl http://root:[email protected]:8888/config-client/development/master

6. La mise en œuvre du client

Ensuite, prenons soin du client. Ce sera une application client très simple, composée d’un contrôleur REST avec une méthode GET .

La configuration, pour récupérer notre serveur, doit être placée dans un fichier de ressources nommé bootstrap.application , car ce fichier (comme son nom l’indique) sera chargé très tôt au démarrage de l’application:

@SpringBootApplication
@RestController
public class ConfigClient {

    @Value("${user.role}")
    private String role;

    public static void main(String[]args) {
        SpringApplication.run(ConfigClient.class, args);
    }

    @RequestMapping(
      value = "/whoami/{username}",
      method = RequestMethod.GET,
      produces = MediaType.TEXT__PLAIN__VALUE)
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello!
          You're %s and you'll become a(n) %s...\n", username, role);
    }
}

En plus du nom de l’application, nous mettons également le profil actif et les détails de connexion dans notre b _ootstrap.properties _ :

spring.application.name=config-client
spring.profiles.active=development
spring.cloud.config.uri=http://localhost:8888
spring.cloud.config.username=root
spring.cloud.config.password=s3cr3t

Pour tester, si la configuration est correctement reçue de notre serveur et que le role value est injecté dans notre méthode de contrôleur, nous le bouclons simplement après le démarrage du client:

$> curl http://localhost:8080/whoami/Mr__Pink

Si la réponse est la suivante, notre Spring Cloud Config Server et son client fonctionnent correctement pour l’instant:

Hello! You're Mr__Pink and you'll become a(n) Developer...

7. Cryptage et décryptage

  • Prérequis ** : Pour utiliser des clés de forte cryptographie ainsi que des fonctionnalités de chiffrement et de déchiffrement de Spring, vous devez installer les fichiers de règles de juridiction illimitée de la puissance de la cryptographie Java (JCE) installés sur votre __JVM./www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html[Oracle].

Pour installer, suivez les instructions incluses dans le téléchargement. Certaines distributions Linux fournissent également un paquet installable via leurs gestionnaires de paquets.

Étant donné que le serveur de configuration prend en charge le cryptage et le décryptage des valeurs de propriété, vous pouvez utiliser les référentiels publics comme stockage pour les données sensibles telles que les noms d’utilisateur et les mots de passe. Les valeurs chiffrées sont préfixées de la chaîne \ {chiffrement} et peuvent être générées par un appel REST du chemin '/chiffrement' , si le serveur est configuré pour utiliser une clé symétrique ou une paire de clés.

Un terminal à décrypter est également disponible. Les deux ordinateurs acceptent un chemin contenant des espaces réservés pour le nom de l’application et son profil actuel: ‘/** /\ {nom}/\ {profil}’ . Ceci est particulièrement utile pour contrôler la cryptographie par client. Cependant, avant qu’elles ne deviennent utiles, vous devez configurer une clé cryptographique, ce que nous allons faire dans la section suivante.

  • Conseil: ** Si vous utilisez curl pour appeler l’API de chiffrement/déchiffrement, il est préférable d’utiliser l’option – data-urlencode (au lieu de – data/-d ) ou de définir l’en-tête 'Content-Type' de manière explicite. 'texte simple' . Cela garantit une gestion correcte des caractères spéciaux, tels que ‘’ dans les valeurs chiffrées.

Si une valeur ne peut pas être déchiffrée automatiquement lors de la récupération via le client, sa key est renommée avec le nom lui-même, préfixé par le mot «invalid». Cela devrait empêcher, par exemple, l’utilisation d’une valeur chiffrée comme mot de passe.

  • Astuce: ** Lors de la configuration d’un référentiel contenant des fichiers YAML, vous devez entourer vos valeurs chiffrées et préfixées de guillemets simples! Avec Propriétés, ce n’est pas le cas.

7.1. Gestion des clés

Le serveur de configuration est activé par défaut pour chiffrer les valeurs de propriété de manière symétrique ou asymétrique.

  • Pour utiliser la cryptographie symétrique ** , il vous suffit de définir la propriété ’encrypt.key ’ de votre application.properties sur un secret de votre choix __. Sinon, vous pouvez transmettre la variable d’environnement ENCRYPT KEY .

  • Pour la cryptographie asymétrique ** , vous pouvez définir ’encrypt.key ’ sur une valeur de chaîne codée PEM ou configurer un keystore à utiliser.

Parce que nous avons besoin d’un environnement hautement sécurisé pour notre serveur de démonstration, nous avons choisi la dernière option et généré un nouveau magasin de clés, comprenant une paire de clés RSA , avec le Java keytool en premier:

$> keytool -genkeypair -alias config-server-key \
       -keyalg RSA -keysize 4096 -sigalg SHA512withRSA \
       -dname 'CN=Config Server,OU=Spring Cloud,O=Baeldung' \
       -keypass my-k34-s3cr3t -keystore config-server.jks \
       -storepass my-s70r3-s3cr3t

Après cela, nous ajoutons le fichier de clés créé à application.properties de notre serveur et le réexécutons:

encrypt.key-store.location=classpath:/config-server.jks
encrypt.key-store.password=my-s70r3-s3cr3t
encrypt.key-store.alias=config-server-key
encrypt.key-store.secret=my-k34-s3cr3t

À l’étape suivante, nous pouvons interroger le noeud final de chiffrement et ajouter la réponse en tant que valeur à une configuration de notre référentiel:

$> export PASSWORD=$(curl -X POST --data-urlencode d3v3L \
       http://root:[email protected]:8888/encrypt)
$> echo "user.password=$PASSWORD" >> config-client-development.properties
$> git commit -am 'Added encrypted password'
$> curl -X POST http://root:[email protected]:8888/refresh

Pour tester, si notre configuration fonctionne correctement, nous allons modifier la classe ConfigClient et redémarrer notre client:

@SpringBootApplication
@RestController
public class ConfigClient {

    ...

    @Value("${user.password}")
    private String password;

    ...
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello!
          You're %s and you'll become a(n) %s, " +
          "but only if your password is '%s'!\n",
          username, role, password);
    }
}

Une dernière requête sur notre client nous indiquera si notre valeur de configuration est correctement déchiffrée:

$> curl http://localhost:8080/whoami/Mr__Pink
Hello! You're Mr__Pink and you'll become a(n) Developer, \
  but only if your password is 'd3v3L'!

7.2. Utilisation de plusieurs clés

Si vous souhaitez utiliser plusieurs clés pour le chiffrement et le déchiffrement, par exemple: une clé dédiée pour chaque application servie, vous pouvez ajouter un autre préfixe sous la forme \ {nom: valeur} entre le préfixe \ { la valeur de la propriété codée par BASE64__.

Le serveur de configuration comprend des préfixes comme \ {secret: my-crypto-secret} ou \ {clé: mon-alias-clé} presque prêts à l’emploi. La dernière option nécessite un fichier de clés configuré dans votre application.properties . Ce fichier de clés est recherché pour un alias de clé correspondant.

user.password={cipher}{secret:my-499-s3cr3t}AgAMirj1DkQC0WjRv...
user.password={cipher}{key:config-client-key}AgAMirj1DkQC0WjRv...

Pour les scénarios sans magasin de clés, vous devez implémenter un @ Bean de type TextEncryptorLocator qui gère la recherche et renvoie un objet TextEncryptor pour chaque clé.

7.3. Utilisation des propriétés chiffrées

Si vous souhaitez désactiver la cryptographie côté serveur et gérer le déchiffrement des valeurs de propriété localement, vous pouvez insérer les éléments suivants dans le fichier application.properties de votre serveur:

spring.cloud.config.server.encrypt.enabled=false

De plus, vous pouvez supprimer toutes les autres propriétés ‘encrypt. ** ’ Pour désactiver les terminaux REST .

8. Conclusion

Nous pouvons maintenant créer un serveur de configuration pour fournir un ensemble de fichiers de configuration d’un référentiel Git aux applications clientes.

Il y a quelques autres choses que vous pouvez faire avec un tel serveur.

Par exemple:

  • Servir la configuration au format YAML ou Properties au lieu de __JSON

également avec les espaces réservés résolus. Ce qui peut être utile, lorsque vous l’utilisez dans des environnements autres que Spring, où la configuration n’est pas directement mappée sur un PropertySource__.

  • Servir des fichiers de configuration en texte brut - éventuellement avec

espaces réservés résolus. Cela peut être utile par exemple pour fournir une configuration de journalisation dépendante de l’environnement.

  • Incorporer le serveur de configuration dans une application, où il se configure

elle-même à partir d’un référentiel Git , au lieu de s’exécuter en tant qu’application autonome servant des clients. Par conséquent, certaines propriétés d’amorce doivent être définies et/ou l’annotation @ EnableConfigServer doit être supprimée, ce qui dépend du cas d’utilisation.

  • Rendre le serveur de configuration disponible sur le service Spring Netflix Eureka

découverte et activer la découverte automatique du serveur dans les clients de configuration. Cela devient important si le serveur n’a pas d’emplacement fixe ou s’il se déplace dans son emplacement.

Pour terminer, vous trouverez le code source de cet article sur Github .