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

Переместите свою конфигурацию mTLS из кодовой базы в сервисную сетку!

Задумывались ли вы когда-нибудь о том, как облегчить свою кодовую базу? Возможно, эта статья для вас. С тегами java, istio, kubernetes, микросервисы.

Вы когда-нибудь задумывались, можете ли вы перенести реализацию, связанную с обменом данными через 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 ResponseEntity clientEndpoint() {
    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.

Конфигурация настолько проста, насколько это возможно.

Выполните следующие действия:

  1. Создайте секрет в кластере K8S, который содержит необходимые данные. Структура secret должна выглядеть следующим образом:

    а затем примените его:

  2. Добавление ресурсов, специфичных для Istio:

    • Служебная запись – описывает API, который является внешним по отношению к сетке
    • Виртуальная служба – перенаправляет трафик во внешнюю систему через порт 80 (http) на порт 443 (http на https)
    • Правило назначения – определяет политику для применения MTLS при маршрутизации трафика во внешнюю систему и указывает каталог сертификатов для использования
  3. Настройте свое развертывание так, чтобы оно монтировало файлы с сертификатами. Для этих целей в аннотациях sidecar.is tio.io/userVolume и sidecar.is tio.io/userVolumeMount используются. Ниже вы можете найти пример развертывания с примененными изменениями.

    Обратите внимание, что в sidecar.is tio.io/userVolume необходимо использовать имя секрета, созданного на шаге 1. В sidecar.is tio.io/user Монтирование тома Путь для монтирования тома должен соответствовать пути, указанному в определении DestinationRule.

  4. Проверьте конфигурацию.

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

    Далее, пришло время проверить обработку соединения mTLS. Теперь выполните запрос HTTP к внешней системе внутри контейнера приложения.

    Вот так!

  5. | HTTP-вызов проксируется через sidecar, и кроме того, успешно установлено соединение mTLS.

    Измените код вашего приложения. В моем примере код приложения будет упрощен до: Без какой-либо специальной настройки

Резюме

Добиться переноса реализаций из кода приложения в servicemesh было довольно просто. Благодаря этому для нашего приложения прозрачно знать, как защищено соединение. Кодовая база приложения более понятна и не зависит от внешних требований безопасности системы.

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

Если у вас есть какие-либо мысли или вопросы, не стесняйтесь комментировать. Примеры кода можно найти на my GitHub . Следуйте за мной дальше Твиттер .

Оригинал: “https://dev.to/piotrekst/move-your-mtls-configuration-from-the-codebase-to-a-service-mesh-50dg”