← Назад к вопросам

Возможна ли реализация https коммуникации между сервисами, развернутыми локально?

2.0 Middle🔥 101 комментариев
#REST API и микросервисы#Безопасность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

HTTPS коммуникация между локальными сервисами

Да, абсолютно возможно! На самом деле, это отличная практика для development окружения, чтобы избежать неприятных сюрпризов при деплое на production.

Способ 1: Self-signed сертификаты

Это самый быстрый способ для локальной разработки.

Создание самоподписанного сертификата

# Создаём приватный ключ и сертификат
keytool -genkey -alias localhost -keyalg RSA -keysize 2048 -keystore keystore.p12 -storepass password123 -validity 365

# Ответьте на вопросы (CN должен быть localhost или IP адрес)
What is your first and last name?
  [Unknown]: localhost
What is the name of your organizational unit?
  [Unknown]: dev
What is the name of your organization?
  [Unknown]: MyCompany
What is the name of your City or Locality?
  [Unknown]: Moscow
What is the name of your State or Province?
  [Unknown]: Moscow
What is the two-letter country code for this unit?
  [Unknown]: RU
Is CN=localhost, OU=dev, O=MyCompany, L=Moscow, ST=Moscow, C=RU correct?
  [yes]: yes

Конфигурация Spring Boot

# application.yml
server:
  port: 8443
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: password123
    key-store-type: PKCS12
    key-alias: localhost

Запуск

# Сервис теперь доступен по HTTPS
curl --insecure https://localhost:8443/api/health
# или
curl -k https://localhost:8443/api/health  # -k = --insecure

Способ 2: Использование mkcert

Модернее и удобнее. Создаёт сертификаты, которые браузер и curl автоматически доверяют.

Установка

# macOS
brew install mkcert

# Linux
wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
chmod +x mkcert-v1.4.4-linux-amd64
sudo mv mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert

# Windows
choco install mkcert

Создание сертификатов

# Инициализируем CA
mkcert -install

# Создаём сертификаты для localhost
mkcert -pkcs12 localhost 127.0.0.1 ::1

# Результат: localhost.p12

Spring Boot конфигурация

server:
  port: 8443
  ssl:
    key-store: classpath:localhost.p12
    key-store-password: changeit
    key-store-type: PKCS12
    key-alias: localhost

Теперь работает без --insecure!

# Работает как обычное HTTPS
curl https://localhost:8443/api/health
# No certificate warnings!

Способ 3: Docker Compose с HTTPS

version: '3.8'
services:
  service-a:
    image: myapp:latest
    ports:
      - "8443:8443"
    environment:
      - SERVER_SSL_ENABLED=true
      - SERVER_SSL_KEY_STORE=/etc/ssl/keystore.p12
      - SERVER_SSL_KEY_STORE_PASSWORD=password123
    volumes:
      - ./keystore.p12:/etc/ssl/keystore.p12
    networks:
      - backend

  service-b:
    image: myapp:latest
    ports:
      - "9443:8443"
    environment:
      - SERVICE_A_URL=https://service-a:8443
      - SSL_VERIFY_HOSTNAME=false  # Для самоподписанных
    depends_on:
      - service-a
    networks:
      - backend

networks:
  backend:
    driver: bridge

Способ 4: RestTemplate/WebClient с игнорированием сертификатов

Когда нужно обращаться к HTTPS сервису с самоподписанным сертификатом:

RestTemplate (старый способ)

public class SslUtils {
    public static RestTemplate createTrustAllRestTemplate() throws Exception {
        // Создаём SSL контекст, который доверяет всем сертификатам
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(
            null,
            new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }},
            new SecureRandom()
        );
        
        // Также игнорируем hostname verification
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
            .setSSLContext(sslContext)
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
        
        HttpClient httpClient = httpClientBuilder.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        
        return new RestTemplate(factory);
    }
}

// Использование
@Configuration
public class RestClientConfig {
    @Bean
    public RestTemplate restTemplate() throws Exception {
        return SslUtils.createTrustAllRestTemplate();
    }
}

WebClient (современный способ)

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() throws Exception {
        // SSL контекст
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(
            null,
            new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }},
            new SecureRandom()
        );
        
        HttpClient httpClient = HttpClient.create()
            .secure(sslSpec -> sslSpec
                .sslContext(sslContext)
                .handshakeTimeout(Duration.ofSeconds(10))
            );
        
        return WebClient.builder()
            .clientConnector(new ReactorNettyClientRequestFactory(
                HttpClient.create()
                    .secure(sslSpec -> sslSpec
                        .sslContext(sslContext)
                    )
            ))
            .build();
    }
}

Ещё проще: через Spring Boot свойства

# application.yml
spring:
  https:
    proxyProtocol: true
  
feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
@FeignClient(
    name = "service-a",
    url = "https://localhost:8443",
    configuration = FeignClientConfig.class
)
public interface ServiceAClient {
    @GetMapping("/api/health")
    ResponseEntity<String> health();
}

@Configuration
public class FeignClientConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

Способ 5: Использование отдельного CA

Для более реалистичного environment:

# 1. Создаём CA
openssl genrsa -out ca-key.pem 2048
openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem

# 2. Создаём сертификат сервиса
openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -out server.csr -subj "/CN=localhost"
openssl x509 -req -days 365 -in server.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

# 3. Конвертируем в PKCS12
openssl pkcs12 -export -in server-cert.pem -inkey server-key.pem -out keystore.p12 -name localhost

Практический пример: микросервисы

// Service A (port 8443)
@RestController
@RequestMapping("/api")
public class ServiceAController {
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        return ResponseEntity.ok("Data from Service A");
    }
}

// Service B (port 9443) - обращается к Service A
@Service
public class ServiceBClient {
    @Bean
    RestTemplate restTemplate() throws Exception {
        return SslUtils.createTrustAllRestTemplate();
    }
    
    public String getDataFromServiceA() {
        String url = "https://localhost:8443/api/data";
        return restTemplate().getForObject(url, String.class);
    }
}

Рекомендации

Для разработки:

  • Используй mkcert (просто и удобно)
  • Или self-signed сертификаты с --insecure

Для тестирования:

  • Игнорируй сертификат (как показано выше)
  • Используй WebClient с кастомным SSL контекстом

Для production:

  • НИКОГДА не игнорируй сертификаты!
  • Используй Let's Encrypt или корпоративный CA
  • Установи сертификаты в keystore

Заключение

Да, HTTPS локально абсолютно возможно и рекомендуется для:

  • Тестирования SSL-зависимого функционала
  • Имитирования production environment
  • Обнаружения SSL проблем ДО development

Выбирай mkcert, это самый удобный способ.