Я, как и наверняка большинство разработчиков, в процессе разработки и локального тестирования различных сервисов использую незащищённые соединения. Но иногда возникает необходимость в использовании защищённых соединений. Использовать сертификаты, выданные сертифицирующими центрами, в этом случае не совсем логично, т.к. они не бесплатны. Вместо этого логичнее использовать самоподписанные сертификаты. В данной статье я рассмотрю создание самоподписанных сертификатов при помощи консольной утилиты OpenSSL.
В качестве подопытного сервиса будет выступать небольшой REST-сервис на Spring Boot, который я хочу запускать в режиме HTTP2, он должен быть доступен по адресу https://localhost:8080
и https://127.0.0.1:8080
. Для него я и буду создавать самоподписанный сертификат.
Но я не хочу создавать действительно самоподписанный сертификат, подписываемый ключом, для которого он выпускается. Сначала я хочу создать приватный ключ и сертификат, при помощи которых буду подписывать сертификаты для всех моих сервисов, проще говоря, имитировать CA.
Мимикрия под CA
Первым делом я создам приватный ключ и сертификат, которые будут имитировать CA:
В процессе создания OpenSSL спросит пароль для создаваемого ключа. Кстати, именно так создаётся самоподписанный сертификат.
Сертификат для сервиса
Теперь можно создать ключ для сервиса:
Для созданного ключа нужно создать запрос на подпись сертификата:
Теперь нужно подписать запрос при помощи CA-сертификата и ключа. Но перед этим нужно создать файл с расширениями сертификата, которые будут добавлены при подписании — localhost.ext. В расширениях нужно указать, что полученный сертификат не является CA-сертификатом и не может использоваться для подписания других сертификатов, а так же альтернативные имена субъекта.
Теперь можно подписывать:
Для удобства импорта сертификатов root_ca.crt и localhost.crt их можно объединить в цепочку сертификатов следующим образом:
На этом этапе у нас есть всё необходимое для использования SSL в сервисах вроде NGINX или Apache httpd. Однако в большинстве Java-приложений SSL настраивается при помощи хранилищ ключей (keystore), который можно создать следующим образом:
ВАЖНО! Если на этапе создания ключа для приложения было выбрано шифрование ключа, то полученное хранилище нужно импортировать в другое при помощи команды keytool:
Полученное хранилище ключей можно использовать в Java-приложении.
Использование сертификата
Теперь в файле application.yml
можно настроить HTTP2 и SSL следующим образом:
Однако, если я сейчас попробую открыть в браузере адрес https://localhost:8080/api/greeting
, то увижу предупреждение об использовании сайтом сертификата, подписанного недоверенным авторизационным центром.
Решается это добавлением CA-сертификата (root_ca.crt) в список центров сертификации в настройках браузера, после чего можно наблюдать корректную работу, в т.ч. и HTTP2:
CA-сертификат можно добавить в список доверенных сертификатов для всей системы, чтобы ему доверяли различные утилиты вроде cURL. На Ubuntu Linux это можно сделать следующим образом:
Если некоторому Java-приложению требуется работать с вашим сервисом через защищённое соединение, то сертификат необходимо добавить в хранилище доверенных сертификатов (truststore), используемое этим приложением: