Pull to refresh
1936.01

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

Reading time11 min
Views4.1K


Всем приветь!
Часть данного мануала просто перепечатывание старого с адаптацией. Но я пойду дальше и добавлю скрипт, для автоматизации создания 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 именно такой формат ключа и нужен пользователя, для доступа к серверу. В процессе экспорта ключа будет запрошена парольная фраза (пароль) и тут есть один нюанс, а именно для windows и 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", подтверждаем и задаем пароль для новой связки. Следующий шаг — это изменить параметры новой связки ключей для того, что бы не надо было постоянно вводить пароль от связки. Правой кнопкой мыши нажимаем на новую связку и выбираем "Изменить параметры .....", в открывшемся окне ставим галочку в чекбоксе/ах и устанавливаем время простоя, спустя это время система вновь запросит пароль от связки ключей.
Связка готова?
Отлично, тогда импортируем ключ — это можно сделать простым перетаскиванием/перемещением файла ключа.


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


Сервера поднимал тут. Еще использую сервера тут, данный хостинг имеет большое разнообразие локаций по приемлемым ценам.
Благодарю за внимание!


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

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


Tags:
Hubs:
+10
Comments11

Articles

Information

Website
timeweb.cloud
Registered
Founded
Employees
201–500 employees
Location
Россия
Representative
Timeweb Cloud