Здесь я покажу вам, как можно создать свой центр сертификации и выпускать свои сертификаты для ваших тестовых или внутренних веб серверов.
Введение
Само-подписанные ssl-сертификаты бывают нужны в некоторых случаях:
- При работе с тестовыми веб-серверами. Когда вам всё равно требуется протокол https. Или не требуется, но вам просто хочется использовать https вместо http. То удобно иметь свой центр сертификации и для каждого тестового сайта выпускать ssl-сертификаты.
- При работе с внутренними web-серверами. Если у компании есть свой внутренний сайт или веб-приложение. И этот сайт доступен только из внутренней сети компании. То, вероятно, вам захочется использовать протокол https вместо http. А так как доступ к сайту есть у ограниченного числа компьютеров, то на них можно добавить свой корневой ssl-сертификат. И тогда, эти компьютеры начнут доверять внутренним сайтам компании.
Если вы не знаете, что означает доверие к сертификату сайта, то покажу вам следующие скриншоты.
На этом скриншоте, браузер не доверяет сайту, но если нажать на кнопку «Дополнительные«, то вы всё равно сможете перейти на сайт:
А на этом скриншоте браузер доверяет сайту. Об этом говорит то, что сайт открылся без предупреждений и замочек в адресной строке:
В этой статье я проделаю следующее:
- На Debian 11 установлю apache2 и настрою его работу на https (с сертификатами по умолчанию для localhost).
- Покажу что клиенты пока не доверяют этому сертификату.
- Создам центр сертификации на этом же сервере. А именно:
- создам закрытый корневой ключ и открытый корневой ключ (он же корневой сертификат);
- с помощью этой пары ключей буду выпускать сертификаты для доменов;
- установлю выпущенный корневой сертификат на компьютер клиента (на windows);
- с помощью корневого ключа и сертификата, я выпущу ключ и сертификат для домена (для веб-сервера).
- Затем я настрою apache2 на использование созданных мною закрытого ключа и сертификата для веб-сервера. И продемонстрирую вам что клиентский браузер начал доверять сертификату сайту.
- Дальше я установлю и настрою другой веб-сервер — nginx. Настрою его на работу по протоколу https. И продемонстрирую доверие браузера к сайту.
Устанавливаю web-сервер apache2:
$ sudo apt install apache2
Настраиваю его работу по протоколу https:
$ sudo a2enmod ssl $ sudo a2ensite default-ssl.conf $ sudo systemctl restart apache2
Проверяю доверие к ssl-сертификату сайта, открыв его по https:
Как видите, доверия нет.
Создаю центр сертификации
Теория
Протокол HTTPS это объединение протоколов HTTP + SSL/TLS. А протокол TLS это асинхронное шифрование. То есть создаётся пара ключей. И то, что один ключ может зашифровать, другой может расшифровать и наоборот. В протоколе HTTPS эти ключи не равнозначные:
- закрытый ключ — это обычный ключ шифрования применяемый в асинхронном шифровании.
- открытый ключ — это тоже ключ шифрования. Но он дополнительно содержит некоторую информацию, например имя домена, имя организации и другое. Такой ключ называют сертификатом.
А ещё протокол TLS позволяет создавать цепочки сертификатов. То-есть, если браузер доверяет родительскому сертификату, то он автоматически будет доверять и всем дочерним сертификатам. А чтобы создать дочернюю пару ключей, нужно иметь доступ к родительской паре ключей.
Корневая пара ключей обычно не подтверждает никакой домен. А используется для создания промежуточных сертификатов или сертификатов для доменов (для web-серверов).
Обычно, когда создают ssl-сертификат для домена, то для безопасности отнимают у него право создания дочерних сертификатов.
Корневой ключ обычно защищают паролем. Это уже симметричное шифрование, когда зная один ключ (пароль) можно зашифровать и расшифровать файл закрытого ключа.
Сервер на котором создают корневые сертификаты, а затем с их помощью выпускают сертификаты для доменов называют — центр сертификации.
Создаю корневой закрытый ключ
Для создания ssl/tls сертификатов можно использовать утилиту openssl, она не требует админских прав.
Создаю корневой закрытый ключ:
$ openssl genpkey -algorithm RSA -out rootCA.key -aes-128-cbc ....................................+++++ ......................+++++ Enter PEM pass phrase: Verifying - Enter PEM pass phrase:
Разберу эту команду:
- genpkey — команда для создания закрытого ключа;
- -algorithm RSA — алгоритм асинхронного шифрования, именно он используется для выделения открытого ключа из этого закрытого;
- -out rootCA.key — получаемый файл закрытого ключа;
- -aes-128-cbc — алгоритм симметричного шифрования, которым мы зашифруем файл закрытого ключа с помощью пароля. Пароль нужно будет ввести.
Создаю корневой сертификат
Теперь создаю корневой сертификат (открытый ключ):
$ openssl req -x509 -new -key rootCA.key -sha256 -days 3650 -out rootCA.crt Enter pass phrase for rootCA.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:RU State or Province Name (full name) [Some-State]:Moscow Locality Name (eg, city) []:Moscow Organization Name (eg, company) [Internet Widgits Pty Ltd]:Sysadminium Organizational Unit Name (eg, section) []:. Common Name (e.g. server FQDN or YOUR name) []:Sysadminium
Разберу команду:
- req — создаёт сертификаты или запросы на сертификаты;
- -x509 — будем создавать сертификат а не запрос;
- -new — создаём новый сертификат (нужно будет ввести значения некоторых полей в сертификате);
- -key rootCA.key — используемый закрытый ключ, из которого нужно создать открытый;
- -sha256 — алгоритм хеширования, чтобы создать подпись ключа;
- -days 3650 — выпускаем сертификат на 10 лет (обратите внимание что закрытые ключи не имеют срока жизни а сертификаты имеют);
- -out rootCA.crt — получаемый сертификат.
Итак, я создал пару ключей:
$ ls -l root* -rw-r--r-- 1 alex alex 1306 сен 9 11:26 rootCA.crt -rw------- 1 alex alex 1874 сен 9 11:19 rootCA.key
Когда мы будем создавать дочерние сертификаты для доменов, нам понадобится файл с порядковым номером выпускаемых сертификатов. Он должен быть с тем же именем что и корневой ключ, но иметь расширение srl.
Создаю файл порядковых номеров для выпуска сертификатов, в нём следует указать два нуля:
$ nano rootCA.srl 00
Дальше нужно передать корневой сертификат на клиентские компьютеры и установить его в доверенные корневые центры сертификации. Я забираю корневой сертификат по протоколу sftp, показывать этот процесс думаю не нужно.
Установка корневого сертификата на Winows
Устанавливаются сертификаты на Windows очень просто. Дважды щелкаем по сертификату и открывается окно с его свойствами. Дальше нажимаем на кнопку «Установить сертификат«:
Установить можно для текущего пользователя или для всего компьютера. Так как у меня это тестовая установка, я выберу «Текущий пользователь«:
После нажатия на кнопку «Далее» нужно выбрать «Поместить все сертификаты в следующее хранилище» и нажать кнопку «Обзор«:
В открывшемся окне выбираем «Доверенные корневые центры сертификации«:
Затем нажимаем кнопку «ОК«, «Далее» и «Готово«.
И наконец, подтверждаем установку сертификата:
И затем нужно будет ещё раз нажать кнопку «ОК«.
Если вы еще раз откроете свойства сертификата (двойным щелчком по нему), то увидите что система начала ему доверять:
Создаю ключ и сертификат для домена
Теперь, с помощью корневых ключей мы можем создать ключи для домена. У меня будет домен — site.sysadminium.ru.
Утилита openssl не может без конфигурационного файла добавлять некоторые поля. А нам нужно будет в сертификат добавить поле subjectAltName. Без этого поля браузер Chrome не доверяет сертификату.
Поэтому вначале я создаю следующий конфиг:
$ nano sysadminium.cnf [ req ] default_bits = 2048 distinguished_name = req_distinguished_name req_extensions = req_ext [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = RU stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Moscow localityName = Locality Name (eg, city) localityName_default = Moscow organizationName = Organization Name (eg, company) organizationName_default = Sysadminium commonName = Common Name (eg, YOUR name or FQDN) commonName_max = 64 commonName_default = site.sysadminium.ru [ req_ext ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = DNS:site.sysadminium.ru
В блоке [ req ] — настраивается команда req:
- default_bits = 2048 — длина ключа по умолчанию.
- distinguished_name = req_distinguished_name — distinguished_name — это поля в сертификате, например Common Name, organizationName и другие. Для этих полей мы создадим блок req_distinguished_name ниже.
- req_extensions = req_ext — расширение для req, здесь мы можем добавить дополнительные поля в сертификат. А в этом параметре мы просто указываем что ниже будет блок req_ext с дополнительными полями.
Блок [ req_distinguished_name ] — служит для конфигурации полей сертификата.
А блок в блок [ req_ext ] — можно добавить некоторые расширяющие свойства сертификата:
- basicConstraints = CA:FALSE — полученные сертификаты нельзя будет использовать как центр сертификации. Другими словами, забираем у сертификатов для доменов право создавать дочерние сертификаты.
- keyUsage = nonRepudiation, digitalSignature, keyEncipherment — созданный ключ будет иметь следующие свойства: неотказуемость (если ключом что-то подписали то аннулировать подпись невозможно), цифровая подпись (сертификат можно использовать в качестве цифровой подписи), шифрование ключей (сертификат можно использовать для симметричного шифрования). Об этих свойствах на английском хорошо написано здесь.
- subjectAltName = DNS:site.sysadminium.ru — а здесь указываем поле subjectAltName и его значение. Как я уже говорил, без этого поля браузер Chrome не доверяет сертификату.
Создаю закрытый ключ для домена
Теперь я создам закрытый ключ для домена:
alex@deb-11:~$ openssl genpkey -algorithm RSA -out site.key .......................................+++++ .............+++++
Создаю файл запроса для домена
С помощью закрытого ключа для домена создаю файл запроса на сертификат:
$ openssl req -new -key site.key -config sysadminium.cnf -reqexts req_ext -out site.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [RU]: State or Province Name (full name) [Moscow]: Locality Name (eg, city) [Moscow]: Organization Name (eg, company) [Sysadminium]: Common Name (eg, YOUR name or FQDN) [site.sysadminium.ru]:
Обратите внимание, все параметры были использованы из конфига, вручную мне не пришлось ничего вписывать.
Создаю сертификат для домена
Теперь, с помощью корневых ключей, подписываю файл запроса и создаю сертификат для домена:
$ openssl x509 -req -days 730 -CA rootCA.crt -CAkey rootCA.key -extfile sysadminium.cnf -extensions req_ext -in site.csr -out site.crt
Разберу команду:
- x509 — создание сертификата путём подписывания;
- -req — если подписывать будем файл запроса, то нужно использовать эту опцию;
- -days 730 — сертификат я делаю на 2 года;
- -CA rootCA.crt -CAkey rootCA.key — указываю корневую пару ключей;
- -extfile sysadminium.cnf — файл, содержащий расширения сертификатов. Без этой опции расширения из файла запроса не попадут в сертификат;
- -in site.csr -out site.crt — файл запроса и файл сертификата.
После проделанного у меня появились три файла связанных с сертификатом для домена:
$ ls -l site.* -rw-r--r-- 1 alex alex 1257 сен 9 14:27 site.crt # сертификат -rw-r--r-- 1 alex alex 1098 сен 9 14:17 site.csr # запрос -rw------- 1 alex alex 1704 сен 9 14:15 site.key # ключ
Перенастраиваю apache2
Кинем сертификат и ключ в следующие каталоги:
$ sudo cp site.crt /etc/ssl/certs/ $ sudo cp site.key /etc/ssl/private/
И настроим apache2 на использование этих ключей:
$ sudo nano /etc/apache2/sites-enabled/default-ssl.conf SSLCertificateFile /etc/ssl/certs/site.crt SSLCertificateKeyFile /etc/ssl/private/site.key
Применим изменение конфига apache2:
$ sudo systemctl reload apache2
И проверим как открывается наш сайт с клиента на котором установлен наш корневой сертификат:
Как видим, браузер начал доверять нашему тестовому сайту.
Смотрим на сертификат из Chrome
Нажмите на замочек возле адреса сайта (он виден на скриншоте выше). Дальше нажмите на «Безопасное подключение» и на «Действительный сертификат«. Откроются свойства сертификата:
На вкладке «Подробнее» вы можете изучить и остальные свойства.
Например, помните мы указывали алгоритм ассиметричного шифрования — RSA:
А помните, мы создали файл для серийных номеров выпускаемых сертификатов и записали в нём «00». Давайте посмотрим на серийный номер нашего сертификата:
Можем посмотреть на сам открытый ключ:
А в расширениях видно альтернативное имя, которое так нужно браузеру Chrome для доверия к сертификату:
Раньше браузеры проверяли только CN:
А сейчас, если есть альтернативное имя, то они даже не смотрят в параметр Common Name. А Chrome требует это поле и вообще перестал смотреть на Common Name.
Настраиваю веб-сервер Nginx
Ну и наконец я покажу как настроить Nginx на использование наших сертификатов.
Для начала выключу apache2 и установлю nginx:
$ sudo systemctl stop apache2.service $ sudo apt install nginx
И настрою его. Нужно рас-комментировать и поменять значения некоторых полей:
$ sudo nano /etc/nginx/sites-enabled/default listen 443 ssl default_server; listen [::]:443 ssl default_server; ssl_certificate /etc/ssl/certs/site.crt; ssl_certificate_key /etc/ssl/private/site.key;
Применю изменения:
$ sudo systemctl reload nginx
И наконец, проверю доверие к ssl-сертификату сайта, обновив страничку в браузере.
Здесь apache2 создал свою индексную страничку, поэтому оба веб сервера (nginx и apache2) используют одну и туже страницу. Но как вы помните, я отключил apache2, так что у меня точно отвечает nginx.
Итог
Надеюсь я смог объяснить, как сделать свой центр сертификации и начать выпускать свои собственные сертификаты для доменов. Мы создали следующие файлы:
- rootCA.key — корневой закрытый ключ. Используется для создания дочерних сертификатов. Обычно лежит на сервере центра сертификации и зашифрован с помощью пароля.
- rootCA.srl — корневой сертификат. Используется для создания дочерних сертификатов. Его нужно распространить на все ваши компьютеры и установить в хранилище корневых сертификатов. Его тоже можно защитить паролем, но я этого не делал.
- site.key — ключ для домена (для веб сервера). Его можно было сгенерировать на веб-сервере и не передавать на сервер центра сертификации. Но в моём примере был один сервер и для веб-сервера и для центра сертификации.
- site.csr — файл запроса на сертификат для домена. Его также можно было сделать на веб-сервере и передать в центр сертификации, чтобы там выпустить сертификат.
- site.crt — сертификат для домена (для веб сервера). Этот файл создаётся из файла запроса на сертификат с помощью пары корневых ключей.
Также я показал, как использовать созданные сертификаты для настройки веб серверов: apache2 и nginx.
Если вы интересуетесь настройками веб-серверов на Linux, то возможно вам также понравится эта статья:
Здравствуйте!
Большое спасибо Вам за материал, многое стало понятно, хоть ничего и не работает в итоге (не доверяет).
По всей инструкции все действия выполнились успешно.
Мои отличия от Вашей конфигурации:
IP-адрес в локальной сети вместо доменного имени, также указал IP в subjectAltName = DNS:IP.
Срок действия сертификата установил 10 лет, также как и у корневого.
Сервер Lighttpd, но он так же ест по отдельности ключ и сертификат или все вместе в виде *.pem-файла.
Браузеры Хром, Опера, FF, в последнем свое хранилище, а не системное, но все равно сертификату не доверяет, может подскажите куда копать?
Простите за беспокойство, проблема решилась subjectAltName = IP:xxx.xxx.x.xx вместо DNS:имя-сайта
Спасибо что ответили как решили проблему, то есть вы заходите на сервер по IP адресу и сертификат принимается?
Да, этот ключ позволяет корректно работать с IP
Все здорово только криптография (пары ключей) не «асинхронная», а ассиметричная. То есть все, что зашифровано открытым ключом, можно расшифровать парным закрытым ключом. Открытый ключ не является секретом — любой может им воспользоваться, чтобы закрыть доступ к информации для всех, кроме владельца закрытого ключа.