Вы когда-нибудь задумывались, можете ли вы перенести реализацию, связанную с обменом данными через MTLS, с уровня кода на более высокий уровень абстракции? В этой статье я попытаюсь показать вам один из подходов к тому, как облегчить вашу кодовую базу.
Примечание: Примеры кода будут основаны на Java, Spring Boot и Into
Это дело!
У вас есть сервис с бизнес-логикой и некоторой внешней системой, для которой необходимо установить связь через mTLS-соединение.
На картинке выше есть внешняя служба (“красная”), управляемая третьей стороной, к которой мы должны выполнять запросы с использованием mTLS. С другой стороны, служба “blue” управляется вашей командой, где вы несете ответственность за обеспечение реализации защищенного подключения к внешней системе.
Первый подход
Первое решение, которое приходит нам на ум, – это обрабатывать такое соединение непосредственно из кода. В этом случае вы создаете выделенный HttpClient и предоставляете ему все необходимые данные, такие как хранилище ключей (с сертификатом клиента и закрытым ключом), хранилище доверия (с сертификатами сервера) или версию протокола.
Пример решения RestTemplate для обработки соединения mTLS может выглядеть следующим образом:
@Bean("externalServiceRestTemplate") RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder .requestFactory(this::requestFactory) .build(); } private ClientHttpRequestFactory requestFactory() { try { final KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(keyStoreResource.getInputStream(), keyStorePassword.toCharArray()); KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(trustStoreResource.getInputStream(), trustStorePassword.toCharArray()); final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder() .loadKeyMaterial(keyStore, keyStorePassword.toCharArray()) .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .setProtocol("TLSv1.2") .build()); final HttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(socketFactory) .build(); final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); return requestFactory; } catch (Exception e) { e.printStackTrace(); throw new IllegalStateException("Could not create client request factory"); } }
Как вы можете видеть, существует много данных, таких как файлы и парольные фразы, которые необходимо передавать непосредственно в ваш исходный код (например, через K8S secrets, FlexVolumes, AWS Secret Manager и т.д.).
Затем вызов целевой службы основан на подключении правильного экземпляра RestTemplate и выполнении запроса HTTPS.
@Autowired @Qualifier("externalServiceRestTemplate") private RestTemplate restTemplate; @GetMapping("/client-endpoint") public ResponseEntityclientEndpoint() { LOGGER.info("Received request. Calling server via mTLS"); String response = restTemplate.getForObject("https://external.system.com/secured-endpoint", String.class); LOGGER.info("Received response from external server {response={}}", response); return ResponseEntity.ok(response); }
Сервисная сетка спешит на помощь!
В этой статье я не буду углубляться в концепцию того, что такое Service Mesh. Если вы не знакомы с этим термином, я рекомендую вам эту статью Уильяма Моргана
Приведенный ниже пример основан на History, которая является одной из ведущих реализаций service mesh с открытым исходным кодом. Если вас интересует история перейдите к их документации и ознакомьтесь с образцом BookInfo приложение
Идея этого решения заключается в том, чтобы перенести ответственность за установление соединения через mTLS на уровень вне нашего приложения. Давайте позволим Это к сделай это!
На рисунке ниже показано упрощенное объяснение того, как это будет работать. У нас есть наш сервис, перед ним есть контейнер istio-proxy. В нашем случае он будет отвечать за обработку сообщения mTLS.
Наш сервис вызовет внешнюю систему как обычную HTTP-систему, а прокси-сервер обновит соединение до HTTPS и обработает данные, связанные с mTLS.
Конфигурация настолько проста, насколько это возможно.
Выполните следующие действия:
Создайте секрет в кластере K8S, который содержит необходимые данные. Структура secret должна выглядеть следующим образом:
а затем примените его:
Добавление ресурсов, специфичных для Istio:
- Служебная запись – описывает API, который является внешним по отношению к сетке
- Виртуальная служба – перенаправляет трафик во внешнюю систему через порт 80 (http) на порт 443 (http на https)
- Правило назначения – определяет политику для применения MTLS при маршрутизации трафика во внешнюю систему и указывает каталог сертификатов для использования
Настройте свое развертывание так, чтобы оно монтировало файлы с сертификатами. Для этих целей в аннотациях
sidecar.is tio.io/userVolume
иsidecar.is tio.io/userVolumeMount
используются. Ниже вы можете найти пример развертывания с примененными изменениями.Обратите внимание, что в
sidecar.is tio.io/userVolume
необходимо использовать имя секрета, созданного на шаге 1. Вsidecar.is tio.io/user Монтирование тома
Путь для монтирования тома должен соответствовать пути, указанному в определении DestinationRule.Проверьте конфигурацию.
Прежде всего, вы можете убедиться, что ваши сертификаты правильно смонтированы. Чтобы сделать это, просто зайдите в свой модуль и проверьте файлы в настроенном каталоге.
Далее, пришло время проверить обработку соединения mTLS. Теперь выполните запрос HTTP к внешней системе внутри контейнера приложения.
Вот так!
-
| HTTP-вызов проксируется через sidecar, и кроме того, успешно установлено соединение mTLS.
Измените код вашего приложения. В моем примере код приложения будет упрощен до:
Без какой-либо специальной настройки
Резюме
Добиться переноса реализаций из кода приложения в servicemesh было довольно просто. Благодаря этому для нашего приложения прозрачно знать, как защищено соединение. Кодовая база приложения более понятна и не зависит от внешних требований безопасности системы.
Издание также предоставляет простой способ реализации других шаблонов, типичных для микросервисов, таких как политики повторных попыток, прерывание цепи или управление версиями API.
Если у вас есть какие-либо мысли или вопросы, не стесняйтесь комментировать. Примеры кода можно найти на my GitHub . Следуйте за мной дальше Твиттер .
Оригинал: “https://dev.to/piotrekst/move-your-mtls-configuration-from-the-codebase-to-a-service-mesh-50dg”