Включение HTTPS в Spring Boot с помощью сертификатов Azure Key Vault

В этом руководстве показано, как защитить приложения Spring Boot (включая Azure Spring Apps) с помощью TLS/SSL-сертификатов с помощью Azure Key Vault и управляемых удостоверений для ресурсов Azure.

В приложениях Spring Boot для рабочей среды (как в облаке, так и локально) необходимо выполнить сквозное шифрование сетевого трафика с использованием стандартных протоколов TLS. Большинство доступных сертификатов TLS/SSL можно найти в общедоступном корневом центре сертификации (ЦС). Однако иногда это невозможно. Если сертификаты невозможно найти, в приложении должна быть предусмотрена возможность загрузки таких сертификатов, их предоставления для входящих сетевых подключений и принятия для исходящих сетевых подключений.

В приложениях Spring Boot при установке сертификатов, как правило, используется TLS. Сертификаты устанавливаются в локальном хранилище ключей виртуальной машины Java, где выполняется приложение Spring Boot. При использовании Spring в Azure сертификаты не устанавливаются локально. Вместо этого интеграция Spring для Microsoft Azure обеспечивает безопасный и удобный способ использования TLS с помощью Azure Key Vault и управляемого удостоверения для ресурсов Azure.

Diagram showing interaction of elements in this tutorial.

Важно!

В настоящее время начальная версия сертификата Azure Spring Cloud версии 4.x или более поздней не поддерживает TLS/mTLS, они автоматически настраивают клиент сертификата Key Vault. Таким образом, если вы хотите использовать TLS/mTLS, вы не можете перенести его в версию 4.x.

Необходимые компоненты

  • Подписка Azure — создайте бесплатную учетную запись.

  • Поддерживаемый комплект разработчика Java (JDK) версии 11.

  • Apache Maven версии 3.0 или более поздней.

  • Azure CLI.

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

  • Экземпляр виртуальной машины Azure. Если у вас его нет, используйте команду az vm create и образ Ubuntu, предоставленный UbuntuServer, чтобы создать экземпляр виртуальной машины с включенным управляемым удостоверением, назначаемым системой. Предоставьте Contributor роль управляемому удостоверению, назначаемого системой, а затем задайте доступ к scope подписке.

  • Экземпляр хранилища ключей Azure. Если у вас его нет, см. краткое руководство. Создание хранилища ключей с помощью портал Azure.

  • Приложение Spring Boot. Если у вас его нет, создайте проект Maven с помощью Spring Initializr. Обязательно выберите проект Maven и в разделе "Зависимости" добавьте зависимость Spring Web , а затем выберите Java версии 8 или более поздней.

Важно!

Для выполнения действий, описанных в этой статье, требуется spring Boot версии 2.5 или более поздней.

Настройка самозаверяющего TLS/SSL-сертификата

Действия, описанные в этом учебнике, применяются к любому сертификату TLS/SSL (включая самозаверяющий), который хранится непосредственно в Azure Key Vault. Самозаверяющие сертификаты не подходят для использования в рабочей среде, но их удобно использовать для разработки и тестирования приложений.

В этом учебнике используется самозаверяющий сертификат. Сведения о настройке сертификата см. в кратком руководстве по настройке и извлечению сертификата из Azure Key Vault с помощью портал Azure.

Примечание.

После задания сертификата предоставьте виртуальной машине доступ к Key Vault, следуя инструкциям в статье "Назначение политики доступа Key Vault".

Безопасное подключение через TLS/SSL-сертификат

Теперь у вас есть виртуальная машина и экземпляр Key Vault и предоставлен доступ виртуальной машины к Key Vault. В следующих разделах показано, как безопасно подключаться через TLS/SSL-сертификаты из Azure Key Vault в приложении Spring Boot. В этом руководстве показаны следующие два сценария:

  • Запуск приложения Spring Boot с использованием защищенных входящих подключений
  • Запуск приложения Spring Boot с использованием защищенных исходящих подключений

Совет

В следующих шагах код будет упаковен в исполняемый файл и отправлен на виртуальную машину. Не забудьте установить OpenJDK на виртуальной машине.

Запуск приложения Spring Boot с использованием защищенных входящих подключений

Когда tls/SSL-сертификат для входящего подключения поступает из Azure Key Vault, настройте приложение, выполнив следующие действия.

  1. Добавьте следующие зависимости в xml-файл pom.xml :

    <dependency>
       <groupId>com.azure.spring</groupId>
       <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
       <version>3.14.0</version>
    </dependency>
    
  2. Настройте учетные данные Key Vault в файле конфигурации application.properties .

    server.ssl.key-alias=<the name of the certificate in Azure Key Vault to use>
    server.ssl.key-store-type=AzureKeyVault
    server.ssl.trust-store-type=AzureKeyVault
    server.port=8443
    azure.keyvault.uri=<the URI of the Azure Key Vault to use>
    

    Эти значения позволяют приложению Spring Boot выполнить действие загрузки для сертификата TLS/SSL, как упоминалось в начале этого учебника. В следующей таблице описаны значения свойств.

    Свойство Description
    server.ssl.key-alias Значение аргумента --name, переданного в az keyvault certificate create.
    server.ssl.key-store-type Этот параметр должен содержать значение AzureKeyVault.
    server.ssl.trust-store-type Этот параметр должен содержать значение AzureKeyVault.
    server.port Локальный TCP-порт для ожидания передачи данных через HTTPS-подключения.
    azure.keyvault.uri Свойство vaultUri в возвращенных данных JSON из az keyvault create. Это значение сохранено в переменной среды.

    Единственным свойством, относящимся к Key Vault, является azure.keyvault.uri. Приложение выполняется в виртуальной машине, назначаемому системой управляемому удостоверению которой предоставлен доступ к Key Vault. Таким образом, приложению также предоставлен доступ.

    Эти изменения позволяют приложению Spring Boot загрузить сертификат TLS/SSL. На следующем шаге вы позволите приложению выполнить действие принятия для TLS/SSL-сертификата, как упоминание в начале руководства.

  3. Измените файл класса запуска, чтобы он получил следующее содержимое.

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    public class SsltestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SsltestApplication.class, args);
        }
    
        @GetMapping(value = "/ssl-test")
        public String inbound(){
            return "Inbound TLS is working!!";
        }
    
        @GetMapping(value = "/exit")
        public void exit() {
            System.exit(0);
        }
    
    }
    

    Вызов System.exit(0) в рамках вызова REST GET, не прошедшего проверку подлинности, предназначен исключительно для демонстрации. Не используйте System.exit(0) в настоящих приложениях.

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

    • Теперь с помощью Spring Initializr создана аннотация @RestController для класса SsltestApplication.
    • Существует метод, аннотированный с @GetMappingпомощью value вызова HTTP.
    • Метод inbound просто возвращает приветствие, когда браузер выполняет HTTPS-запрос для пути /ssl-test. Метод inbound показывает, как сервер предоставляет сертификат TLS/SSL для браузера.
    • Метод exit приводит к выходу JVM при вызове. Этот метод позволяет упростить выполнение примера в контексте этого учебника.
  4. Выполните следующие команды, чтобы скомпилировать код и упаковать его в исполняемый JAR-файл.

    mvn clean package
    
  5. Убедитесь, что группа безопасности сети, созданная в <your-resource-group-name>, разрешает входящий трафик через порты 22 и 8443 с вашего IP-адреса. Дополнительные сведения о настройке правил группы безопасности сети для входящего трафика см. в разделе о работе с правилами безопасности статьи о создании, изменении и удалении группы безопасности сети.

  6. Разместите исполняемый JAR-файл на виртуальной машине.

    cd target
    sftp azureuser@<your VM public IP address>
    put *.jar
    

    Теперь, когда вы создали приложение Spring Boot и отправите его на виртуальную машину, выполните следующие действия, чтобы запустить его на виртуальной машине и вызвать конечную точку REST.curl

  7. Используйте SSH для подключения к виртуальной машине, а затем запустите исполняемый JAR-файл.

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  8. Откройте новую оболочку Bash и выполните указанную ниже команду, чтобы убедиться, что сервер предоставляет сертификат TLS/SSL.

    curl --insecure https://<your VM public IP address>:8443/ssl-test
    
  9. Вызовите путь exit, чтобы завершить работу сервера и закрыть сетевые сокеты.

    curl --insecure https://<your VM public IP address>:8443/exit
    

Теперь, когда вы видели загрузку и представить действия с самозаверяющим СЕРТИФИКАТом TLS/SSL, внесите некоторые тривиальные изменения в приложение, чтобы увидеть действие принятия , а также.

Запуск приложения Spring Boot с использованием защищенных исходящих подключений

В этом разделе вы измените код в предыдущем разделе, чтобы TLS/SSL-сертификат для исходящих подключений был получен из Azure Key Vault. Поэтому действия по загрузке, предоставлению и принятию выполняются с помощью Azure Key Vault.

  1. Добавьте зависимость клиента Apache HTTP в файл pom.xml :

    <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>4.5.13</version>
    </dependency>
    
  2. Добавьте новую конечную точку REST с именем ssl-test-outbound. Эта конечная точка открывает сокет TLS и проверяет, принимает ли TLS-подключение сертификат TLS/SSL. Замените предыдущую часть класса запуска следующим кодом.

    import java.security.KeyStore;
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import com.azure.security.keyvault.jca.KeyVaultLoadStoreParameter;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContexts;
    
    @SpringBootApplication
    @RestController
    public class SsltestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SsltestApplication.class, args);
        }
    
        @GetMapping(value = "/ssl-test")
        public String inbound(){
            return "Inbound TLS is working!!";
        }
    
        @GetMapping(value = "/ssl-test-outbound")
        public String outbound() throws Exception {
            KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
            KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
                System.getProperty("azure.keyvault.uri"));
            azureKeyVaultKeyStore.load(parameter);
            SSLContext sslContext = SSLContexts.custom()
                                               .loadTrustMaterial(azureKeyVaultKeyStore, null)
                                               .build();
    
            HostnameVerifier allowAll = (String hostName, SSLSession session) -> true;
            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allowAll);
    
            CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
    
            HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
    
            requestFactory.setHttpClient(httpClient);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            String sslTest = "https://localhost:8443/ssl-test";
    
            ResponseEntity<String> response
                = restTemplate.getForEntity(sslTest, String.class);
    
            return "Outbound TLS " +
                (response.getStatusCode() == HttpStatus.OK ? "is" : "is not")  + " Working!!";
        }
    
        @GetMapping(value = "/exit")
        public void exit() {
            System.exit(0);
        }
    
    }
    
  3. Выполните следующие команды, чтобы скомпилировать код и упаковать его в исполняемый JAR-файл.

    mvn clean package
    
  4. Отправьте приложение повторно с помощью той же команды sftp, которая использовалась ранее в рамках этой статьи.

    cd target
    sftp <your VM public IP address>
    put *.jar
    
  5. Запустите приложение на виртуальной машине.

    set -o noglob
    ssh azureuser@<your VM public IP address> "java -jar *.jar"
    
  6. После запуска сервера убедитесь, что он принимает сертификат TLS/SSL. В той же оболочке Bash, где была выполнена предыдущая команда curl, выполните следующую команду.

    curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
    

    Отобразится сообщение Outbound TLS is working!!.

  7. Вызовите путь exit, чтобы завершить работу сервера и закрыть сетевые сокеты.

    curl --insecure https://<your VM public IP address>:8443/exit
    

Теперь вы изучили действия загрузки, предоставления и принятия с использованием самозаверяющего сертификата TLS/SSL, хранящегося в Azure Key Vault.

Развертывание в Azure Spring Apps

Теперь, когда у вас есть приложение Spring Boot, работающее локально, пришло время переместить его в рабочую среду. Azure Spring Apps упрощает развертывание приложений Spring Boot в Azure без каких-либо изменений кода. Эта служба управляет инфраструктурой приложений Spring, благодаря чему разработчики могут сосредоточиться на коде. Azure Spring Apps обеспечивает управление жизненным циклом за счет комплексного мониторинга и диагностики, управления конфигурацией, обнаружения служб, интеграции CI/CD, выполнения сине-зеленых развертываний и прочего. Сведения о развертывании приложения в Azure Spring Apps см. в статье "Развертывание первого приложения в Azure Spring Apps".

Следующие шаги

Дополнительные сведения о Spring и Azure см. в центре документации об использовании Spring в Azure.