Краткое введение в конфигурацию Spring Cloud

1. Обзор

  • Spring Cloud Config ** - это клиент-серверный подход Spring для хранения и обслуживания распределенных конфигураций в различных приложениях и средах.

Это хранилище конфигурации идеально версионировано под управлением версией Git и может быть изменено во время выполнения приложения. Хотя он очень хорошо подходит для приложений Spring, использующих все поддерживаемые форматы файлов конфигурации вместе с такими конструкциями, как Environment , PropertySource или @Value , он может использоваться в любой среде, в которой работает любой язык программирования.

В этой статье мы рассмотрим пример настройки сервера конфигурации с поддержкой Git , его использования на простом сервере приложений REST и настройки безопасной среды, включая зашифрованные значения свойств.

2. Настройка проекта и зависимости

Чтобы подготовиться к написанию кода, мы сначала создадим два новых проекта Maven . Проект сервера основан на https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-config- модуль сервера% 22[spring-cloud-config-server] , а также 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] и ​​ 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] начальные пакеты:

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

Однако для клиентского проекта нам понадобится только 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] и ​​ 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 modules] :

<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. Реализация сервера конфигурации

Основная часть приложения - это класс конфигурации, в частности ссылка:/spring-boot-application-configuration[ @ SpringBootApplication ], которая включает все необходимые настройки через auto-configure annotation @ EnableConfigServer:

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {

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

Теперь нам нужно настроить сервер port , на котором слушает наш сервер, и Git -url, который предоставляет содержимое конфигурации с управлением версиями. Последний может использоваться с такими протоколами, как http , ssh или простой file в локальной файловой системе.

  • Совет: ** Если вы планируете использовать несколько экземпляров сервера конфигурации, указывающих на один и тот же репозиторий конфигурации, вы можете настроить сервер для клонирования вашего хранилища во временную локальную папку. Но имейте в виду частные репозитории с двухфакторной аутентификацией, с ними трудно обращаться! В таком случае их проще клонировать в локальной файловой системе и работать с копией.

Для настройки repository-url также доступны некоторые переменные placeholder и шаблоны поиска ; но это выходит за рамки нашей статьи. Если вам интересно, официальная документация - хорошее место для начала.

Нам также нужно установить имя пользователя и пароль для Basic-Authentication в нашем application.properties , чтобы избежать автоматически сгенерированного пароля при каждом перезапуске приложения:

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. Git-репозиторий как хранилище настроек

Чтобы завершить работу нашего сервера, мы должны инициализировать репозиторий Git под настроенным URL, создать несколько новых файлов свойств и популяризировать их с некоторыми значениями.

Имя файла конфигурации составлено как обычный Spring application.properties , но вместо слова «application» настроенное имя, например используется значение свойства ‘spring.application.name’ клиента, за которым следует тире и активный профиль. Например:

$> 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'
  • Устранение неполадок: ** Если вы столкнулись с проблемами аутентификации, связанными с ssh , дважды проверьте ~/.ssh/known hosts и ~/.ssh/authorized keys на вашем сервере ssh!

5. Запрос конфигурации

Теперь мы можем запустить наш сервер. API-интерфейс с поддержкой Git , предоставляемый нашим сервером, можно запросить по следующим путям:

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

В котором заполнитель \ {label} относится к ветви Git, \ {application} - к имени клиентского приложения, а \ {profile} - к текущему активному профилю приложения клиента.

Таким образом, мы можем получить конфигурацию для нашего запланированного клиента конфигурации, работающего в профиле разработки в ветви master , с помощью:

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

6. Реализация клиента

Далее, давайте позаботимся о клиенте. Это будет очень простое клиентское приложение, состоящее из контроллера REST с одним методом GET .

Конфигурация, чтобы получить наш сервер, должна быть помещена в файл ресурсов с именем bootstrap.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);
    }
}

В дополнение к имени приложения мы также помещаем активный профиль и сведения о соединении в наш 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

Чтобы проверить, правильно ли получена конфигурация с нашего сервера и в методе контроллера введено role value , мы просто свернем ее после загрузки клиента:

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

Если ответ следующий, наш Spring Cloud Config Server и его клиент работают нормально:

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

7. Шифрование и дешифрование

  • Требование ** : Чтобы использовать криптографически надежные ключи вместе с функциями шифрования и дешифрования Spring, вам понадобятся 'Java Cryptography Extension (JCE) Файлы политики неограниченной юрисдикции' , установленные в вашем JVM. Их можно загрузить, например, с Oracle .

Для установки следуйте инструкциям, включенным в загрузку. Некоторые дистрибутивы Linux также предоставляют устанавливаемый пакет через своих менеджеров пакетов.

Поскольку сервер конфигурации поддерживает шифрование и дешифрование значений свойств, вы можете использовать общедоступные репозитории в качестве хранилища для конфиденциальных данных, таких как имена пользователей и пароли. Зашифрованные значения имеют префикс строки \ {cipher} и могут быть сгенерированы с помощью REST-вызова пути ‘/encrypt’ , если сервер настроен на использование симметричного ключа или пары ключей.

Также доступна конечная точка для расшифровки. Обе конечные точки принимают путь, содержащий заполнители для имени приложения и его текущего профиля: ‘/** /\ {name}/\ {profile}’ . Это особенно полезно для управления криптографией для каждого клиента. Однако, прежде чем они станут полезными, вы должны настроить криптографический ключ, который мы сделаем в следующем разделе.

  • Совет: ** Если вы используете curl для вызова API en-/decryption, лучше использовать параметр – data-urlencode (вместо – data/-d ) или установить заголовок Content-Type явно в 'text/plain' . Это обеспечивает правильную обработку специальных символов, таких как in ’, в зашифрованных значениях.

Если значение не может быть дешифровано автоматически при извлечении из клиента, его key переименовывается с самим именем, с префиксом слова «invalid» Это должно предотвратить, например, использование зашифрованного значения в качестве пароля.

  • Совет: ** При настройке репозитория, содержащего файлы YAML, вы должны заключать в зашифрованные и префиксные значения одинарные кавычки! Со свойствами это не так.

7.1. Ключевой менеджмент

По умолчанию сервер конфигурации включен для шифрования значений свойств симметричным или асимметричным способом.

  • Чтобы использовать симметричную криптографию ** , вам просто нужно установить свойство ‘encrypt.key’ в вашем application.properties на выбранный вами секрет __. В качестве альтернативы вы можете передать переменную среды ENCRYPT KEY .

  • Для асимметричной криптографии ** вы можете установить для ‘encrypt.key’ строковое значение в кодировке PEM или настроить использование keystore .

Поскольку для нашего демонстрационного сервера нам нужна среда с высокой степенью защиты, мы выбрали последний вариант и создали новое хранилище ключей, включая пару ключей RSA , с Java keytool first:

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

После этого мы добавляем созданное хранилище ключей в application.properties нашего сервера и перезапускаем его:

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

В качестве следующего шага мы можем запросить конечную точку шифрования и добавить ответ в качестве значения к конфигурации в нашем репозитории:

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

Чтобы проверить, правильно ли работает наша установка, мы модифицируем класс ConfigClient и перезапустим наш клиент:

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

Последний запрос к нашему клиенту покажет нам, если значение нашей конфигурации правильно расшифровано:

$> 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. Использование нескольких ключей

Если вы хотите использовать несколько ключей для шифрования и дешифрования, например: выделенный для каждого обслуживаемого приложения, вы можете добавить другой префикс в форме \ {name: value} между префиксом \ {cipher} и BASE64 -закодированное значение свойства.

Конфигурационный сервер распознает префиксы, такие как \ {secret: my-crypto-secret} или \ {key: my-key-alias} , практически готовые к использованию. Последний вариант требует настроенного хранилища ключей в вашем application.properties . В этом хранилище ключей выполняется поиск подходящего псевдонима ключа.

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

Для сценариев без хранилища ключей вы должны реализовать @ Bean типа TextEncryptorLocator , который обрабатывает поиск и возвращает TextEncryptor -Object для каждого ключа.

7.3. Обслуживание зашифрованных свойств

Если вы хотите отключить криптографию на стороне сервера и локально обрабатывать дешифрование значений свойств, вы можете поместить следующее в application.properties вашего сервера:

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

Кроме того, вы можете удалить все другие свойства «encrypt. ** », Чтобы отключить конечные точки REST .

8. Заключение

Теперь мы можем создать сервер конфигурации для предоставления набора файлов конфигурации из репозитория Git клиентским приложениям.

Есть несколько других вещей, которые вы можете сделать с таким сервером.

Например:

  • Служите конфигурации в формате YAML или Properties вместо __JSON

также с разрешенными заполнителями. Что может быть полезно при использовании его в средах, отличных от Spring, где конфигурация напрямую не сопоставлена ​​с PropertySource__.

  • Служите простыми текстовыми файлами конфигурации - в свою очередь, опционально с

решенные заполнители. Это может быть полезно, например, для предоставления зависящей от среды конфигурации регистрации.

  • Вставить сервер конфигурации в приложение, где он настраивает

сам из репозитория Git , вместо того, чтобы работать как отдельное приложение, обслуживающее клиентов. Поэтому некоторые свойства начальной загрузки должны быть установлены и/или аннотация @ EnableConfigServer должна быть удалена, что зависит от варианта использования.

  • Сделать сервер конфигурации доступным в сервисе Spring Netflix Eureka

обнаружение и включение автоматического обнаружения сервера в клиентах конфигурации. Это становится важным, если у сервера нет фиксированного местоположения или он перемещается в своем местоположении.

И в заключение, вы найдете исходный код этой статьи на Github .