Web-сервер с двухуровневой иерархией ЦС. Авторизация по SSL

от автора

Всем приветь!
Часть данного мануала просто перепечатывание старого с адаптацией. Но я пойду дальше и добавлю скрипт, для автоматизации создания ssl сертификатов и их отзывов. Однако и на этом я не остановлюсь и сделаю инструкцию для создания безопасности web-сервера таким образом, чтобы доступ к нему был только у пользователей, имеющих сертификаты.

Для реализации нам понадобится три сервера/виртуальной машины: RootCA — корневой центр сертификации, SubCA — подчиненный/подписывающий центр сертификации, web-сервер — сервер, для которого мы будем подписывать ssl сертификат.

Создание двухуровневой иерархии ЦС и подпись ssl сертификата

Идем на RootCA и создаем центр сертификации:

cd ~ wget -P ~/ https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.8/EasyRSA-3.0.8.tgz tar xvf EasyRSA-3.0.8.tgz mv ~/EasyRSA-3.0.8 ~/easyrsa-rootca/ cd ~/easyrsa-rootca/ cp vars.example vars vim vars

Находим блок, удалим # и подставим свои значения. Дабы при подписании сертификатов не вводить наши данные мы их пропишем тут (данный блок нужен для того, чтобы в подписанных сертификатах была информация о том кому принадлежат сертификаты):

#set_var EASYRSA_REQ_COUNTRY    "US" #set_var EASYRSA_REQ_PROVINCE   "California" #set_var EASYRSA_REQ_CITY           "San Francisco" #set_var EASYRSA_REQ_ORG            "Copyleft Certificate Co" #set_var EASYRSA_REQ_EMAIL          "me@example.net" #set_var EASYRSA_REQ_OU     "My Organizational Unit"

Далее находим следующие установки, удалим # и редактируем их значения. Эти директивы отвечают за сроки жизни сертификатов (первая — за срок сертификата ЦС, вторая — за срок сертификата, который подписывается, третья — за сертификат с данными об отозванных сертификатах):

#set_var EASYRSA_CA_EXPIRE          3650         #-->  3650 #set_var EASYRSA_CERT_EXPIRE    3650         #-->  1825 #set_var EASYRSA_CRL_DAYS            180    

После редактирования файла vars и установки необходимых нам значений создадим ЦС:

./easyrsa init-pki ./easyrsa build-ca nopass

Если будет только один CA (RootCA), то переходим к выпуску сертификатов.
Теперь переходим на SubCA и повторяем те же самые шаги с небольшими изменениями:

cd ~ wget -P ~/ https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.8/EasyRSA-3.0.8.tgz tar xvf EasyRSA-3.0.8.tgz mv ~/EasyRSA-3.0.8 ~/easyrsa-subca/ cd ~/easyrsa-subca/ cp vars.example vars vim vars

Находим блок, удалим # и подставим свои значения:

#set_var EASYRSA_REQ_COUNTRY    "US" #set_var EASYRSA_REQ_PROVINCE   "California" #set_var EASYRSA_REQ_CITY           "San Francisco" #set_var EASYRSA_REQ_ORG            "Copyleft Certificate Co" #set_var EASYRSA_REQ_EMAIL          "me@example.net" #set_var EASYRSA_REQ_OU     "My Organizational Unit"

Далее находим следующие установки, удалим # и редактируем их значения:

#set_var EASYRSA_CA_EXPIRE          3650         #-->  1825 #set_var EASYRSA_CERT_EXPIRE    3650         #-->  365 #set_var EASYRSA_CRL_DAYS            180

Еще раз создадим ЦС и запрос на подпись сертификата и передадим его RootCA:

./easyrsa init-pki ./easyrsa build-ca subca nopass scp pki/reqs/ca.req user@ip_RootCA:/tmp

Возвращаемся на RootCA и подписываем сертификат и передаем его обратно на SubCA, а так же прихватим сертификат RootCA.crt. После этого сервер RootCA нам больше не нужен и в целях безопасности его лучше выключить. Все сертификаты теперь будут выпускаться на подписывающем сервере SubCA:

cd ~/easyrsa-rootca/ ./easyrsa import-req /tmp/ca.req SubCA ./easyrsa sign-req ca SubCA scp pki/issued/SubCA.crt user@ip_SubCA:/tmp scp pki/ca.crt user@ip_SubCA:/tmp/RootCA.crt

Переходим на SubCA и перемещаем подписанный сертификат в СЦ. Дабы в будущем не путаться в сертификатах, оставим имя сертификата SubCA.crt и сделаем на него символьную ссылку:

mv /tmp/SubCA.crt ~/easyrsa-subca/pki/ ln -s ~/easyrsa-subca/pki/SubCA.crt ~/easyrsa-subca/pki/ca.crt

Идем в директорию ЦС и создадим файл Диффи-Хелмана для повышения безопасности web-сервера. Файл Диффи-Хелмана (Diffie-Hellman) необходим для реализации протокола, позволяющего использовать небезопасный канал для получения общего секретного ключа. Этот ключ будет в дальнейшем использоваться для защищенного обмена данными с помощью алгоритмов симметричного шифрования.

cd ~/easyrsa-subca/ ./easyrsa gen-dh

Переходим к финальной части, а именно выпуск ssl сертификата и конфигурация web-сервера:

./easyrsa gen-req your_site_name nopass ./easyrsa sign-req server you_site_name 

Создадим директорию для хранения сертификатов, перенесем туда сертификаты и подпишем запрос:

mkdir -p ~/ssl_cert/name_web_server mv pki/dh.pem ~/ssl_cert/name_web_server/ cp pki/SubCA.crt ~/ssl_cert/name_web_server/ cp pki/{issued,private}/your_site_name.* ~/ssl_cert/name_web_server/ sudo rm pki/reqs/your_site_name.req

Для работы сервера нам надо сделать цепочку сертификатов (объединить сертификат your_site_name.crt и SubCA.crt в fullchain.crt):

cat ~/ssl_cert/name_web_server/your_site_name.crt ~/ssl_cert/name_web_server/SubCA.crt > ~/ssl_cert/name_web_server/your_site_name.fullchain.crt

Cертификаты готовы, и нам надо перенести их на web-сервер и указать к ним путь:

sudo chown -R user:user ~/ssl_cert/name_web_server     #(optional) scp ~/ssl_cert/name_web_server/*.{crt,key,pem} user@ip_web_server:/tmp

Идем на web-сервер создадим директорию для хранения сертификатов и перенесем их туда:

mkdir ~/ssl_cert/ mkdir ~/ssl_cert/{key,cert} sudo chmod 600 ~/ssl_cert/key/ mv /tmp/*.{crt,pem} ~/ssl_cert/cert/ sudo mv /tmp/*.key ~/ssl_cert/key/

Пропишем пути к сертификатам в Apache2 или Nginx.

Nginx

sudo vim /etc/nginx/sites-available/your_site_name.com

Находим блок с путями к сертификатам и меняем его:

... listen 443 ssl;       ssl_certificate /home/user/ssl_cert/cert/your_site_name.fullchain.crt;     ssl_certificate_key /home/user/ssl_cert/key/your_site_name.com.key;     ssl_dhparam /home/user/ssl_cert/cert/dh.pem; ...

Перезапускаем web-службу:

systemctl restart nginx

Apache2

sudo vim /etc/apache2/sites-available/your_site_name.com.conf

Находим блок с путями к сертификатам и меняем его (данная схема подходит для Apache2 версии 2.4.8 и новее):

... SSLCertificateFile      /home/user/ssl_cert/cert/your_site_name.fullchain.crt SSLCertificateKeyFile /home/user/ssl_cert/key/your_site_name.key SSLOpenSSLConfCmd DHParameters /home/user/ssl_cert/cert/dh.pem ...

Для Apache2 версии 2.4.7 и ниже объединяем сертификаты и редактируем конфигурацию:

cat /home/user/ssl_cert/cert/your_site_name.fullchain.crt /home/user/ssl_cert/cert/dh.pem > /home/user/ssl_cert/cert/your_site_name.dhfullchain.pem sudo vim /etc/apache2/sites-available/your_site_name.com.conf

... SSLEngine On   SSLCertificateFile /home/user/ssl_cert/cert/your_site_name.dhfullchain.pem   SSLCertificateKeyFile /home/user/ssl_cert/key/your_site_name.key ...

Перезапускаем web-службу:

systemctl restart apache2

Осталось сделать последний ход: на web-сервере мы разместили самоподписанный сертификат, значит для любого клиента этот сертификат не является надежным и безопасным. Для этого мы должны дать системе корневой сертификат и сказать, что всем сертификатам, которые подписаны этим ЦС и его подчиненными ЦС, мы можем доверять. Для этого мы берем сертификат RootCA.crt отдаем пользователям, которые будут ходить на наш web-сервер и устанавливаем в систему как «доверенные корневые центры сертификации». Теперь у нас все готово и можно работать дальше.

Скрипты для автоматизации создания ssl сертификатов и их отзывов

Прежде чем запустить скрипт мы должны создать инфраструктуру для хранения сертификатов и сами скрипты. Данные скрипты мы поместим на сервере SubCA, он у нас подписывающий. Скрипты можно отправить копипастом на сервер или установить git и клонировать репозиторий.
В процессе создания пользовательские сертификаты будут экспортироваться в формат .p12 именно такой формат ключа и нужен пользователя, для доступа к серверу. В процессе экспорта ключа будет запрошена парольная фраза (пароль) и тут есть один нюанс, а именно для windiws и linux систем она не обязательна — это на ваше усмотрение, а вот для macOS нужна. Ниже я объясню каким образом наиболее безболезненно установить сертификат на системе macOS, потому что там приходится доставать бубен и исполнять танец дождя.

git clone

Установим git и клонируем репозиторий:

apt install git -y git clone https://github.com/dumasti/create_ssl.git mkdir -p ~/ssl_scripts/ssl_certs mv create_ssl/*.sh ssl_scripts/ rm -r create_ssl chmod +x ~/ssl_scripts/*.sh

Если скрипты не клонируем, тогда создадим необходимые директории:

mkdir -p ~/ssl_scripts/ssl_certs touch ~/ssl_scripts/{create_ssl,revoke_ssl}.sh chmod +x ~/ssl_scripts/*.sh

Теперь в файлы запишем сам скрипт:

vim ~/ssl_scripts/create_ssl.sh

#!/bin/bash  echo "For whom/for what the certificate? ((S)erver/(U)ser/(C)ancel) " while true; do         read -r         object=$REPLY         if [[ "$object" == "S" ]] || [[ "$object" ==  "s" ]]; then                 echo "What is the name of your site? "                 read -r                 name=$REPLY                 break         elif [[ "$object" == "U" ]] || [[ "$object" ==  "u" ]]; then                 echo "What is the name of your user? "                 read -r                 name=$REPLY                 break         elif [[ "$object" == "C" ]] || [[ "$object" == "c" ]]; then                 exit         else                 echo "Correct answer is S/s/U/u/C/c only!"         fi done echo "Which CA to use? " echo `ls ~/ | grep -E -i 'CA|easy|rsa'` read -r ca=$REPLY cd ~/$ca/ echo "How long to sign the certificate (in days)? 365 - 1 year 730 - 2 years 1095 - 3 years 1460 - 4 years 1825 - 5 years " read -r year_new=$REPLY mkdir -p ~/ssl_scripts/ssl_certs/$name year_old=`cat ~/$ca/vars | grep "set_var EASYRSA_CERT_EXPIRE"` sed -i "s/$year_old/set_var EASYRSA_CERT_EXPIRE $year_new/" ~/$ca/vars ./easyrsa gen-req $name nopass if [[ "$object" == "S" ]] || [[ "$object" ==  "s" ]]; then         ./easyrsa sign-req server $name         echo "Do you need dh.pem? (y/n)"         read -r         dh=$REPLY         if [[ "$dh" == "y" ]]; then                 if [ -e pki/dh.pem ]; then                         mv pki/dh.pem ~/ssl_scripts/ssl_certs/$name                 else                         ./easyrsa gen-dh                         mv pki/dh.pem ~/ssl_scripts/ssl_certs/$name                 fi         fi         cp ~/$ca/pki/issued/$name.crt ~/ssl_scripts/ssl_certs/$name         cp ~/$ca/pki/RootCA.crt ~/ssl_scripts/ssl_certs/$name         cp ~/$ca/pki/private/$name.key ~/ssl_scripts/ssl_certs/$name         cat ~/$ca/pki/issued/$name.crt ~/$ca/pki/SubCA.crt > ~/ssl_scripts/ssl_certs/$name/$name.fullchain.crt elif [[ "$object" == "U" ]] || [[ "$object" ==  "u" ]]; then         ./easyrsa sign-req client $name         ./easyrsa export-p12 $name         cp ~/$ca/pki/issued/$name.crt ~/ssl_scripts/ssl_certs/$name         cp ~/$ca/pki/RootCA.crt ~/ssl_scripts/ssl_certs/$name         cp ~/$ca/pki/private/$name.{key,p12} ~/ssl_scripts/ssl_certs/$name fi echo "$name `date | cut -d " " -f2,3,4` $ca $year_new $object  CREATE" >> ~/ssl_scripts/cert_base cd ~/ssl_scripts/ssl_certs/ tar -cvf $name/$name.tar $name/* tar -czvf $name/$name.tar.gz $name/* whoami=`whoami` sudo chown -R $whoami:$whoami ~/ssl_scripts/ssl_certs/$name/ echo "DONE!"

Хочу отметить тот факт, что хоть скрипт и предлагает подписывать сертификат на 5 лет, но iOS устройства считают такие сертификаты ненадежными и для поддержки таких устройств сертификаты нужно подписывать не больше чем на 3 года.

vim ~/ssl_scripts/revoke_ssl.sh

#!/bin/bash  echo "Which CA to use? " echo `ls ~/ | grep -E -i 'CA|easy|rsa'` read -r ca=$REPLY cd ~/$ca/ echo "For whom/for what to revoke the certificate? ((S)erver/(U)ser/(C)ancel) " echo `ls pki/issued/ | cut -d '.' -f 1` read -r name_crt=$REPLY if [ -e ~/ssl_scripts/ssl_certs/revoke ]; then         printf "yes" | ./easyrsa revoke $name_crt         ./easyrsa gen-crl         cp pki/crl.pem ~/ssl_scripts/ssl_certs/revoke/ else         mkdir ~/ssl_scripts/ssl_certs/revoke         printf "yes" | ./easyrsa revoke $name_crt         ./easyrsa gen-crl         cp pki/crl.pem ~/ssl_scripts/ssl_certs/revoke/ fi rm ~/$ca/pki/issued/$name_crt.crt rm ~/$ca/pki/private/$name_crt.* rm -r ~/ssl_scripts/ssl_certs/$name_crt echo "$name_crt `date | cut -d " " -f2,3,4` $ca REVOKE" >> ~/ssl_scripts/cert_base echo "DONE!"

Данные скрипты интерактивны, их нужно только запустить, а после отвечать на вопросы.

Настройка доступа к web-серверу по сертификатам

Бывают такие случаи, когда нужно ограничить доступ к сайту, но не закрывать сервер или сайт от доступа извне (из интернета). В таких случаях можно прибегнуть к простому решению, а именно разрешить доступ на сайт только по пользовательскому ssl сертификату. Сервер его проверит и если все устроит, то пустит пользователя. Выше я уже привел скрипты, которые сами все сделают, вам надо только ответить на вопросы для чего/кого выпускается сертификат и срок «жизни» сертификата. Скрипты заточены под двухуровневую иерархию, а значит будут работать на SubCA. Для тех, кто хочет выпускать сертификаты имея только один центр сертификации приведу тут инструкцию. Она проста: для начала возвращаемся в начало статьи и создаем CA как там (RootCA). Далее мы выпускаем сертификат для веб сервера и, если нужна авторизация пользователей по ssl, клиента:

cd ~/easyrsa-rootca/ ./easyrsa gen-dh ./easyrsa gen-req <FQDN> nopass ./easyrsa sign-req server <FQDN> mkdir -p ~/ssl_cert/<FQDN> cp pki/dh.pem ~/ssl_cert/<FQDN>/ cp pki/private/<FQDN>.key ~/ssl_cert/<FQDN>/ cp pki/issued/<FQDN>.crt ~/ssl_cert/<FQDN>/ # Если нужна авторизация пользователей, то ./easyrsa gen-req <user_name> nopass ./easyrsa sign-req client <user_name> ./easyrsa export-p12 <user_name> mkdir ~/ssl_cert/<user_name> cp pki/private/dara.p12 ~/ssl_cert/<user_name>/ cp pki/ca.crt ~/ssl_cert/{<FQDN>,<user_name>}/RootCA.crt

Далее отправляем серверные сертификаты на сервер, в настройках прописываем к ним пути и перезапускаем веб сервер, а пользовательский сертификат отдаем пользователю, который должен его установить в системе.

Конфигурация для Apache2 и Nginx проста, нам надо только добавить пару строк и прописать путь к сертификату. Приступим:

Nginx

vim /etc/nginx/sites-available/your_site_name.com

... ssl_client_certificate       /home/user/ssl_cert/cert/RootCA.crt; ssl_verify_client            on; ssl_verify_depth            1; #ssl_crl                        /home/user/ssl_cert/cert/crl.pem; # --убрать комментарий для активации отзыва сертификатов ...

Перезапускаем сервис:

systemctl restart nginx

image

Apache2

vim /etc/apache2/sites-available/your_site_name.com.conf

... SSLCACertificateFile /home/user/ssl_cert/cert/RootCA.crt #SSLCARevocationFile /home/user/ssl_cert/cert/crl.pem # --убрать комментарий для активации отзыва сертификатов SSLVerifyClient require SSLVerifyDepth  10 ...

Перезапускаем Apache2:

systemctl restart apache2

Apache на Windows

Настройка авторизации в Windows не отличается от Debian за исключением пути к conf файлу:

C:\Apache24\conf\httpd.conf

Далее прописываем настройка в конце файла и указываем пути к сертификатам:

LoadModule ssl_module modules/mod_ssl.so Listen 443 <VirtualHost *:443>     ServerAdmin webmaster@localhost      #DocumentRoot "${SRVROOT}/htdocs"     DocumentRoot "C:\Apache24\htdocs"     ServerName localhost:443     ServerAlias www.localhost:443      ErrorLog "${SRVROOT}/logs/error-ssl.log"     TransferLog "${SRVROOT}/logs/access-ssl.log"      SSLEngine on     SSLCertificateFile      "C:\Apache24\localhost\localhost.fullchain.crt"     #SSLCertificateFile      "C:\Apache24\localhost\localhost.crt"     SSLCertificateKeyFile "C:\Apache24\localhost\localhost.key"     SSLOpenSSLConfCmd DHParameters "C:\Apache24\localhost\dh.pem"     SSLCACertificateFile "C:\Apache24\localhost\RootCA.crt"     #SSLCARevocationFile "C:\Apache24\localhost\crl.pem"      SSLVerifyClient require     SSLVerifyDepth  10 </VirtualHost>

Сохраняем настройка и перезапускаем Apache в PowerShell (запускаем от имени администратора):

c:\Apache24\bin\httpd.exe -k restart

Когда все готово осталось попасть на сайт используя пользовательский ssl сертификат. Выпускаем сертификат используя скрипт выше или своим способом, который не запрещен религией и устанавливаем этот сертификат. Как я уже говорил выше, сертификат можно запаролить при выпуске. Самое главное — сертификат должен быть с расширением .p12.

Установка на macOS

Сертификат уже на маке? Тогда давайте его установим. Путей может быть несколько: дважды нажимаем на сертификат и вводим его пароль система сама решит в какую связку ключей его добавить, но может случиться так, что ключ будет добавлен в связку от которой постоянно придется вводить пароль — это геморно и я не нашел способа это исправить. Мы пойдем другим путем: открываем «Связка ключей» и правой кнопкой мыши нажимаем на «Связки ключей, созданные пользователем», выбираем «Новая связка ключей…» и задаем имя, а так же место хранения «Keychains», подтверждаем и задаем пароль для новой связки. Следующий шаг — это изменить параметры новой связки ключей для того, что бы не надо было постоянно вводить пароль от связки. Правой кнопкой мыши нажимаем на новую связку и выбираем «Изменить параметры …..», в открывшемся окне ставим галочку в чекбоксе/ах и устанавливаем время простоя, спустя это время система вновь запросит пароль от связки ключей.
Связка готова?
Отлично, тогда импортируем ключ — это можно сделать простым перетаскиванием/перемещением файла ключа.

После того, как сертификат будет установлен в системе при переходе на сайт браузер запросит пользовательский сертификат, мы его выбираем и подтверждаем. Все готово!

Благодарю за внимание!

Благодарность за помощь

Благодарю за редакторские правки Дарью Гулькович, а так же за проверку и тестирование мануала Станислава Карасовского.


ссылка на оригинал статьи https://habr.com/ru/company/timeweb/blog/666284/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *