Introdução rápida à configuração do Spring Cloud

Introdução rápida à configuração do Spring Cloud

1. Visão geral

*_Spring Cloud Config_* é a abordagem cliente/servidor da Spring para armazenar e servir configurações distribuídas em vários aplicativos e ambientes.

Esse armazenamento de configuração é idealmente versionado sob o controle de versão Git e pode ser modificado no tempo de execução do aplicativo. Embora ele se encaixe muito bem nos aplicativos Spring usando todos os formatos de arquivo de configuração suportados, juntamente com construções como Environment, _link:/properties-with-spring [PropertySource ou @Value] _, ele pode ser usado em qualquer ambiente executando qualquer linguagem de programação.

Neste artigo, vamos nos concentrar em um exemplo de como configurar um servidor de configuração suportado por Git, usá-lo em um servidor de aplicativos REST simples e configurar um ambiente seguro, incluindo valores de propriedade criptografados.

*2. Configuração do projeto e dependências *

Para se preparar para escrever algum código, criamos dois novos projetos Maven primeiro. O projeto do servidor depende de _https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-config- servidor% 22 [spring-cloud-config-server] _, bem como o _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] _ e _https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org .springframework.boot% 22% 20AND% 20a% 3A% 22spring-boot-starter-web% 22 [spring-boot-starter-web] _ pacotes iniciais:

<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>

No entanto, para o projeto cliente, precisaremos apenas de _https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A% 22spring-cloud-starter-config% 22 [spring-cloud-starter-config] _ e os _https://search.maven.org/classic/#search%7Cgav%7Cgav%7C1%7Cg%3A%22org.springframework.boot% 22% 20AND% 20a% 3A% 22spring-boot-starter-web% 22 [módulos de inicialização de inicialização da web] 22:

<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. Uma implementação do servidor de configuração *

A parte principal do aplicativo é uma classe de configuração - mais especificamente, um link:/spring-boot-application-configuration [_ @ SpringBootApplication_] - que obtém toda a instalação necessária através da anotação auto-configure _ @ EnableConfigServer: _

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {

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

Agora, precisamos configurar o port do servidor no qual nosso servidor está escutando e um Git-url que fornece nosso conteúdo de configuração controlado por versão. Este último pode ser usado com protocolos como http, ssh ou um simples file em um sistema de arquivos local.

*Dica:* Se você planeja usar várias instâncias do servidor de configuração apontando para o mesmo repositório de configurações, é possível configurar o servidor para clonar seu repositório em uma pasta temporária local. Mas esteja ciente de repositórios particulares com autenticação de dois fatores, eles são difíceis de manusear! Nesse caso, é mais fácil cloná-los no sistema de arquivos local e trabalhar com a cópia.

Existem também algumas variáveis ​​de placeholder e padrões de pesquisa para configurar o repository-url disponível; mas isso está além do escopo de nosso artigo. Se você estiver interessado, a documentação oficial é um bom lugar para começar.

Também precisamos definir um nome de usuário e uma senha para o Basic-Authentication em nosso application.properties para evitar uma senha gerada automaticamente em cada reinicialização do aplicativo:

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. Um repositório Git como armazenamento de configuração *

Para concluir nosso servidor, precisamos inicializar um repositório Git sob o URL configurado, criar alguns novos arquivos de propriedades e popularizá-los com alguns valores.

O nome do arquivo de configuração é composto como um application.properties Spring normal, mas, em vez da palavra "aplicativo", um nome configurado, por exemplo, o valor da propriedade ‘spring.application.name' do cliente é usado, seguido por um traço e o perfil ativo. Por exemplo:

$> 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'
*Solução de problemas:* Se você encontrar problemas de autenticação relacionados ao _ssh_, verifique _ ~/.ssh/known_hosts_ e _ ~/.ssh/allowed_keys_ no seu servidor ssh!

*5. Consultando a configuração *

Agora podemos iniciar nosso servidor. A API de configuração suportada por Git fornecida por nosso servidor pode ser consultada usando os seguintes caminhos:

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

No qual o espaço reservado _ \ {label} _ se refere a uma ramificação Git, _ \ {application} _ ao nome do aplicativo do cliente e o _ \ {profile} _ ao perfil de aplicativo ativo atual do cliente.

Portanto, podemos recuperar a configuração do nosso cliente de configuração planejado em execução no perfil de desenvolvimento na filial master via:

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

===* 6. A implementação do cliente *

Em seguida, vamos cuidar do cliente. Este será um aplicativo cliente muito simples, consistindo em um controlador REST com um método GET.

A configuração, para buscar nosso servidor, deve ser colocada em um arquivo de recurso chamado bootstrap.application, porque esse arquivo (como o nome indica) será carregado muito cedo enquanto o aplicativo é iniciado:

@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);
    }
}

Além do nome do aplicativo, também colocamos o perfil ativo e os detalhes da conexão em nosso bootstrap.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

Para testar, se a configuração é recebida adequadamente do nosso servidor e o role value é injetado no nosso método do controlador, simplesmente o enrolamos após a inicialização do cliente:

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

Se a resposta for a seguinte, nosso Spring Cloud Config Server e seu cliente estão funcionando bem por enquanto:

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

===* 7. Criptografia e descriptografia *

*Requisito* : Para usar chaves criptograficamente fortes, juntamente com os recursos de criptografia e descriptografia do Spring, você precisa dos _'Java Cryptography Extension (JCE) Arquivos de Política de Jurisdição de Força Ilimitada'_ instalados em sua _JVM._ Estes podem ser baixados, por exemplo, em http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html[Oracle]. Para instalar, siga as instruções incluídas no download. Algumas distribuições Linux também fornecem um pacote instalável por meio de seus gerenciadores de pacotes.

Como o servidor de configuração oferece suporte à criptografia e descriptografia de valores de propriedade, você pode usar repositórios públicos como armazenamento para dados confidenciais, como nomes de usuário e senhas. Os valores criptografados são prefixados com a string _ \ {cipher} _ e podem ser gerados por uma chamada REST para o caminho _ ‘/encrypt'_, se o servidor estiver configurado para usar uma chave simétrica ou um par de chaves.

Um ponto final para descriptografar também está disponível. Os dois pontos de extremidade aceitam um caminho que contém espaços reservados para o nome do aplicativo e seu perfil atual: _ ‘/*/\ {name}/\ {profile} '_. Isso é especialmente útil para controlar a criptografia por cliente. No entanto, antes que se tornem úteis, você deve configurar uma chave criptográfica que faremos na próxima seção.

*Dica:* Se você usar curl para chamar a API en-/decriptografia, é melhor usar a opção _ – data-urlencode_ (em vez de _ – data/-d_) ou defina o cabeçalho 'Content-Type' explícito para _'text/plain'_. Isso garante uma manipulação correta de caracteres especiais como ‘+ 'nos valores criptografados.

Se um valor não puder ser descriptografado automaticamente durante a busca pelo cliente, sua key será renomeada com o próprio nome, prefixado pela palavra 'inválido'. Isso deve impedir, por exemplo, o uso de um valor criptografado como senha.

*Dica:* Ao configurar um repositório contendo arquivos YAML, você deve colocar entre aspas e valores criptografados e prefixados aspas simples! Com Propriedades, esse não é o caso.

7.1 Gerenciamento de chaves

Por padrão, o servidor de configuração está habilitado para criptografar valores de propriedades de maneira simétrica ou assimétrica.

*Para usar criptografia simétrica* , basta definir a propriedade _‘encrypt.key'_ no seu _application.properties_ como um segredo de sua escolha __.__ Como alternativa, você pode transmitir a variável de ambiente _ENCRYPT_KEY_.
*Para criptografia assimétrica* , você pode definir _‘encrypt.key'_ como um valor de string codificado por _PEM_ ou configurar uma _keystore_ para usar.

Como precisamos de um ambiente altamente seguro para nosso servidor de demonstração, escolhemos a última opção e geramos um novo keystore, incluindo um par de chaves RSA, com o keytool Java primeiro:

$> 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

Depois disso, adicionamos o keystore criado ao application.properties do nosso servidor e o executamos novamente:

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

Como próximo passo, podemos consultar o ponto de extremidade de criptografia e adicionar a resposta como valor a uma configuração em nosso repositório:

$> 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

Para testar, se nossa configuração funcionar corretamente, estamos modificando a classe ConfigClient e reiniciando nosso cliente:

@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);
    }
}

Uma consulta final contra nosso cliente nos mostrará, se nosso valor de configuração estiver sendo descriptografado corretamente:

$> 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 Usando várias chaves

Se você desejar usar várias chaves para criptografia e descriptografia, por exemplo: uma dedicada para cada aplicativo atendido, poderá adicionar outro prefixo no formato _ \ {name: value} _ entre o prefixo _ \ {cipher} _ e o valor da propriedade codificada por BASE64.

O servidor de configuração entende prefixos como _ \ {secret: my-crypto-secret} _ ou _ \ {key: my-key-alias} _ quase prontos. A última opção precisa de um keystore configurado em seu application.properties. Esse keystore é procurado por um alias de chave correspondente. Por exemplo:

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

Para cenários sem keystore, é necessário implementar um _ @ Bean_ do tipo TextEncryptorLocator que lida com a pesquisa e retorna um TextEncryptor-Object para cada chave.

7.3. Servindo propriedades criptografadas

Se você desejar desativar a criptografia do lado do servidor e manipular a descriptografia de valores de propriedade localmente, poderá colocar o seguinte no application.properties do seu servidor:

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

Além disso, você pode excluir todas as outras propriedades ‘encrypt. *'Para desativar os pontos de extremidade REST.

===* 8. Conclusão*

Agora, podemos criar um servidor de configuração para fornecer um conjunto de arquivos de configuração de um repositório Git para aplicativos clientes. Existem algumas outras coisas que você pode fazer com esse servidor.

Por exemplo:

  • Servir configuração no formato YAML ou Properties em vez de JSON – também com espaços reservados resolvidos. O que pode ser útil ao usá-lo em ambientes que não sejam Spring, nos quais a configuração não é mapeada diretamente para um PropertySource.

  • Servir arquivos de configuração de texto sem formatação - opcionalmente com espaços reservados resolvidos. Isso pode ser útil, por exemplo, para fornecer uma configuração de log dependente do ambiente.

  • Incorpore o servidor de configuração a um aplicativo, no qual ele se configura a partir de um repositório Git, em vez de executar como aplicativo independente, atendendo a clientes. Portanto, algumas propriedades de auto-inicialização devem ser definidas e/ou a anotação _ @ EnableConfigServer_ deve ser removida, o que depende do caso de uso.

  • Disponibilize o servidor de configuração na descoberta de serviço Spring Netflix Eureka e ative a descoberta automática de servidores em clientes de configuração. Isso se torna importante se o servidor não tiver um local fixo ou se mover nesse local.

E para finalizar, você encontrará o código fonte deste artigo _https://github.com/eugenp/tutorials/tree/master/spring-cloud/spring-cloud-config [no Github] _.