Рубрики
Без рубрики

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

Краткое введение в использование репозитория git в качестве хранилища для конфигурации нашего проекта с использованием Spring Cloud.

Автор оригинала: baeldung.

1. Обзор

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

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

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

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

Чтобы подготовиться к написанию некоторого кода, мы сначала создаем два новых проекта Maven . Серверный проект опирается на модуль spring-cloud-config-server , а также на пакеты spring-boot-starter-security и spring-boot-starter-web starter:


    org.springframework.cloud
    spring-cloud-config-server


    org.springframework.boot
    spring-boot-starter-security


    org.springframework.boot
    spring-boot-starter-web

Однако для клиентского проекта нам понадобятся только spring-cloud-starter-config и spring-boot-starter-web модули :


    org.springframework.cloud
    spring-cloud-starter-config


    org.springframework.boot
    spring-boot-starter-web

3. Реализация Сервера Конфигурации

Основной частью приложения является класс конфигурации – более конкретно @SpringBootApplication – который извлекает всю необходимую настройку через автоконфигурацию аннотацию @EnableConfigServer:

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

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

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

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

Нам также необходимо установить имя пользователя и пароль для 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
spring.security.user.name=root
spring.security.user.password=s3cr3t

4. Репозиторий Git в качестве хранилища конфигурации

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

Имя файла конфигурации составляется как обычная пружина application.properties , но вместо слова “приложение” используется сконфигурированное имя, например значение свойства ‘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 -backend, предоставляемый нашим сервером, можно запросить по следующим путям:

/{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);
    }

    @GetMapping(
      value = "/whoami/{username}",  
      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);
    }
}

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

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

$> 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” . Это обеспечивает правильную обработку специальных символов, таких как ” + ” в зашифрованных значениях.

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

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

7.1. CSRF

По умолчанию Spring Security включает защиту CSRF для всех запросов, отправленных в наше приложение.

Поэтому, чтобы иметь возможность использовать конечные точки /encrypt и /decrypt , давайте отключим для них CSRF:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf()
          .ignoringAntMatchers("/encrypt/**")
          .ignoringAntMatchers("/decrypt/**");

        super.configure(http);
    }
}

7.2. Управление Ключами

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

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

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

Поскольку нам нужна высокозащищенная среда для нашего демо-сервера, мы выбрали последний вариант и создали новое хранилище ключей, включая пару ключей 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

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

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

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

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

Чтобы проверить, правильно ли работает наша настройка, мы изменяем класс Config 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);
    }
}

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

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

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

Сервер конфигурации понимает префиксы, такие как {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 типа Локатор текстового шифратора , который обрабатывает поиск и возвращает TextEncryptor -Объект для каждого ключа.

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

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

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

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

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

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

Например:

  • Подавайте конфигурацию в формате YAML или Properties вместо JSON – также с разрешенными заполнителями. Что может быть полезно при его использовании в средах, отличных от Spring, где конфигурация напрямую не сопоставляется с PropertySource .
  • Подавайте файлы конфигурации с открытым текстом – в свою очередь, необязательно с разрешенными заполнителями. Это может быть полезно, например, для обеспечения зависящей от среды конфигурации ведения журнала.
  • Внедрите сервер конфигурации в приложение, где он настраивается из репозитория Git , вместо того, чтобы работать как автономное приложение, обслуживающее клиентов. Поэтому необходимо установить некоторые свойства начальной загрузки и/или удалить аннотацию @EnableConfigServer , что зависит от варианта использования.
  • Сделайте сервер конфигурации доступным в Spring Netflix Eureka service discovery и включите автоматическое обнаружение серверов в клиентах конфигурации. Это становится важным, если сервер не имеет фиксированного местоположения или перемещается в своем местоположении.

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