Всем приветь!
Часть данного мануала просто перепечатывание старого с адаптацией. Но я пойду дальше и добавлю скрипт, для автоматизации создания ssl сертификатов и их отзывов. Однако и на этом я не остановлюсь и сделаю инструкцию для создания безопасности web-сервера таким образом, чтобы доступ к нему был только у пользователей, имеющих сертификаты.
Для реализации нам понадобится три сервера/виртуальной машины: RootCA — корневой центр сертификации, SubCA — подчиненный/подписывающий центр сертификации, web-сервер — сервер, для которого мы будем подписывать 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.
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
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-сервер и устанавливаем в систему как "доверенные корневые центры сертификации". Теперь у нас все готово и можно работать дальше.
Прежде чем запустить скрипт мы должны создать инфраструктуру для хранения сертификатов и сами скрипты. Данные скрипты мы поместим на сервере SubCA, он у нас подписывающий. Скрипты можно отправить копипастом на сервер или установить git и клонировать репозиторий.
В процессе создания пользовательские сертификаты будут экспортироваться в формат .p12 именно такой формат ключа и нужен пользователя, для доступа к серверу. В процессе экспорта ключа будет запрошена парольная фраза (пароль) и тут есть один нюанс, а именно для windiws и linux систем она не обязательна — это на ваше усмотрение, а вот для macOS нужна. Ниже я объясню каким образом наиболее безболезненно установить сертификат на системе macOS, потому что там приходится доставать бубен и исполнять танец дождя.
Установим 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!"
Данные скрипты интерактивны, их нужно только запустить, а после отвечать на вопросы.
Бывают такие случаи, когда нужно ограничить доступ к сайту, но не закрывать сервер или сайт от доступа извне (из интернета). В таких случаях можно прибегнуть к простому решению, а именно разрешить доступ на сайт только по пользовательскому 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 проста, нам надо только добавить пару строк и прописать путь к сертификату. Приступим:
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
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
Настройка авторизации в 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.
Сертификат уже на маке? Тогда давайте его установим. Путей может быть несколько: дважды нажимаем на сертификат и вводим его пароль система сама решит в какую связку ключей его добавить, но может случиться так, что ключ будет добавлен в связку от которой постоянно придется вводить пароль — это геморно и я не нашел способа это исправить. Мы пойдем другим путем: открываем "Связка ключей" и правой кнопкой мыши нажимаем на "Связки ключей, созданные пользователем", выбираем "Новая связка ключей..." и задаем имя, а так же место хранения "Keychains", подтверждаем и задаем пароль для новой связки. Следующий шаг — это изменить параметры новой связки ключей для того, что бы не надо было постоянно вводить пароль от связки. Правой кнопкой мыши нажимаем на новую связку и выбираем "Изменить параметры .....", в открывшемся окне ставим галочку в чекбоксе/ах и устанавливаем время простоя, спустя это время система вновь запросит пароль от связки ключей.
Связка готова?
Отлично, тогда импортируем ключ — это можно сделать простым перетаскиванием/перемещением файла ключа.
После того, как сертификат будет установлен в системе при переходе на сайт браузер запросит пользовательский сертификат, мы его выбираем и подтверждаем. Все готово!
Благодарю за внимание!
Благодарю за редакторские правки Дарью Гулькович, а так же за проверку и тестирование мануала Станислава Карасовского.
Комментарии (6)
DonAlPAtino
20.05.2022 19:08А что-нибудь готовое с веб интерфейсом для управления клиентскими сертификатами можете посоветовать?
dumasti Автор
20.05.2022 22:38Я не знаю таких. Если только webmin, но может он то, что вам надо или нет - не знаю.
AlexVWill
Для Апача указанных настроек может быть недостаточно
Возможно (но не обязательно) в конфиг /etc/apache2/sites-available/your_site_name.com.conf надо будет добавить еще
Кстати, у меня на Apache2 все попытки настроить доступ через самоподписанный SSL заканчивались провалом, браузеры ни в какую не хотели принимать созданный таким образом Р12 при доступе к сайту, авторизованному через созданные crt. Решилось все созданием pem сертификатов
и указанием в конфиге апача таких вот параметров
Вот так оно взлетело...
dumasti Автор
Сделайте все как тут и сработает)
Что касается SSLEngine - выше я вставлял это в пример. И этот параметр подразумевается сам собой т.к. все это делается сразу под https. Будет ли авторизация работать по http не знаю, не пробовал и даже не задумывался об этом. Возможно вы правы в том, что надо было явно указать этот параметр и в пункте включения авторизации.
AlexVWill
Не, я не спорю, что прикрутить EasyRSA вместо OpenSSL задача любопытная и вполне решаемая. Просто я описал свой опыт работы в данном направлении, что-то у меня с этим не срослось, а вот на OpenSSL сработало. Так что если у кого то будут те же грабли, есть возможность их решить.
Я в свою очередь попробую на досуге ваш вариант, может и получится, вполне вероятно я там где то кривыми руками что-то не то делал.
dumasti Автор
Ну вариант с двухуровневой иерархией у меня тоже с 5-ого раза получился, а с одним СА было куда проще. И в первоначальном варианте я тоже использовал не голый Easy-RSA, а вперемежку с openssl.