Сразу хочу отметить, что тут я больший упор делал на настройку ЦС чем на OpenVPN.
Перед тем как мы начнем, я расскажу кому это может пригодиться на своем примере.
У меня была задача создать систему для большой компании таким образом, чтобы сертификаты сервера OpenVPN подписывались только одним человеком, VPN серверов достаточно много, под каждый отдел поднято по несколько VPN серверов. Сотрудников (клиентов) еще больше и контролировать (выписывать/отзывать) сертификаты всякий раз, когда пришел/ушел сотрудник очень тяжкая ноша (не говоря уже о временных сотрудниках). Сотрудников каждого отдела контролирует начальник отдела, который и выписывает или отзывает сертификаты новым/старым сотрудникам соответственно.
Для чего нужны сертификаты и цифровые ключи очень много говорилось и я не буду повторять других авторов, но если коротко, то:
- для удостоверения надежности (происходит двойное рукопожатие) клиент и сервер убеждаются в том кто они, можно ли друг другу доверять и устанавливают соединение;
- шифрования/дешифрования;
- исключения Man in the middle (MITM) дабы быть уверенным, что кто-то не перехватывает сообщения/трафик;
- для создания зашифрованных паролей, что повышает безопасность и усложняет доступ злоумышленников на хост.
Принцип работы многоуровневой иерархии ЦС заключается в том, что ЦС верхнего уровня (RootCA) свой сертификат подписывает сам себе на достаточно большой период времени (но тут дело сугубо индивидуальное), каждый следующий ниже в иерархии ЦС или сервис подписывают свои сертификаты у вышестоящего ЦС (обычная бюрократия) с условием, что сертификат нижестоящего должен иметь срок действия не более чем вполовину меньше срока действия вышестоящего сертификата.
При создании ЦС создается два файла: ca.crt открытый ключ и ca.key закрытый ключ.
Закрытый ключ должен быть защищен и не должен передаваться третьим лицам.
Когда надо создать подчиняющийся/подписывающий ЦС, мы создаем на нем закрытый ключ и запрос на подпись у RootCA.
Откуда компьютеры и пользователи по всему миру будут знать, что могут доверять какому-либо сервису или сайту, спросите вы? Все просто (ну в теории), Открытый ключ ЦС (RootCA) помещается на пользовательские компьютеры и эти компьютеры доверяют всем сертификатам, которые были выпущены данным ЦС. На практике это конечно сложнее и не дешево. Но в пределах своей компании достаточно легко осуществимо.
Для реализации нам необходимо три сервера. В данной мануале будем использовать debian 9. Сервера назовем согласно их применению: OpenVPN, SubCA, RootCA.
Все действия выполняем под пользователем не рутом.
Для этого ваш пользователь должен быть в группе sudo.
Если sudo на сервере не установлено, тогда авторизовываемся под root:
# su - root# apt-get install sudo -y# usermod -aG sudo username# exit
На всех серверах устанавливаем необходимые утилиты (утилиты могут отличаться в зависимости от верований и убеждений, обязательной является wget, ufw, vim т.к. тут я привел команды с данными утилитами):
# sudo apt-get update# sudo apt-get upgrade# sudo apt-get install wget curl net-tools ufw vim -y# cd ~# wget -P ~/ https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.4/EasyRSA-3.0.4.tgz# tar xvf EasyRSA-3.0.4.tgz
На сервере OpenVPN устанавливаем openvpn:
# sudo apt-get install openvpn -y
Переходим на сервер RootCA. Тут нам надо создать файл, откуда easyrsa будет брать значения переменных:
# mv ~/EasyRSA-3.0.4 ~/easyrsa/# cd ~/easyrsa/# 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_EXPIRE3650 #--> 3650#set_var EASYRSA_CERT_EXPIRE3650 #--> 1825
Далее:
# ./easyrsa init-pki
При запуске следующей команды будет запрошен CN. Можно оставит значение по умолчанию, но лучше ввести имя идентифицирующее хост (RootCA). Значение nopass говорит о том, что пароль создавать не надо:
# ./easyrsa build-ca nopass
Переходим на сервер SubCA и выполняем аналогичные шаги с небольшими изменениями:
# mv ~/EasyRSA-3.0.4 ~/easyrsa/# cd ~/easyrsa/# 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_EXPIRE3650 #--> 1825#set_var EASYRSA_CERT_EXPIRE3650 #--> 365
Далее:
# ./easyrsa init-pki
При запуске следующей команды будет запрошен CN. Можно оставит значение по умолчанию, но лучше ввести имя идентифицирующее хост (SubCA). Значение subca говорит о том, что мы создаем подчиненный ЦС и нам надо создать запрос на подпись сертификата:
# ./easyrsa build-ca subca nopass
Далее находим файл ~/easyrsa/pki/reqs/ca.req (это и есть тот самый запрос) и передаем его серверу RootCA (можно использовать два способа: WinSCP и scp):
# scp ~/easyrsa/pki/reqs/ca.req user@ip_RootCA:/tmp
Переходим на сервер RootCA и подписываем запрос. Перед тем как подписать запрос, мы должны импортировать его в рабочую директорию. для подписания сертификата для подчиненного ЦС используем атрибут ca и имя сертификата (можно его назвать ca, но дабы не путаться, назовем его именем сервера, которому его подписываем, а когда передадим его серверу, переименуем):
# cd ~/easyrsa/# ./easyrsa import-req /tmp/ca.req SubCA# ./easyrsa sign-req ca SubCA
Будет запрошено подтверждение, надо ввести yes.
Возвращаем SubCA подписанный сертификат.
# scp ~/easyrsa/pki/issued/SubCA.crt user@ip_SubCA:/tmp
Переходим на сервер SubCA и перемещаем сертификат в рабочую директорию easyrsa:
# mv /tmp/SubCA.crt ~/easyrsa/pki/ca.crt
На данный момент у нас уже есть корневой ЦС и подписанный корневым вторичный ЦС.
Теперь займемся сервером OpenVPN. В его настройке некоторые предыдущие шаги повторяются. Переходим на сервер OpenVPN.
# cd ~/easyrsa/# ./easyrsa init-pki
Теперь начнем создавать сертификаты на подпись. Мы создадим ключ Диффи-Хеллмана (dh.pem/dh2048.pem/dh1024.pem), который будет использоваться при обмене ключами, и создадим подпись HMAC (ta.key), для усиления функции проверки целостности TLS.
Сертификаты для сервера OpenVPN мы будем подписывать на RootCA, а сертификаты для пользователей мы будем подписывать на SubCA. Сразу создадим директорию где мы будем складывать ключи, сертификаты и конфигурации клиентов.
# mkdir -p ~/client-configs/files/# mkdir ~/client-configs/keys/# chmod 700 ~/client-configs/# sudo mkdir /etc/openvpn/vpnsrv1/# ./easyrsa gen-req vpnsrv1 nopass# ./easyrsa gen-req dumasti nopass# ./easyrsa gen-dh# sudo openvpn --genkey --secret ta.key# cp /home/dumasti/easyrsa/pki/private/dumasti.key ~/client-configs/keys/# sudo cp /home/dumasti/easyrsa/pki/dh.pem /etc/openvpn/vpnsrv1/# sudo cp /home/dumasti/easyrsa/ta.key /etc/openvpn/vpnsrv1/# sudo cp /home/dumasti/easyrsa/ta.key ~/client-configs/keys/# sudo cp /home/dumasti/easyrsa/pki/private/vpnsrv1.key /etc/openvpn/vpnsrv1/# scp ~/easyrsa/pki/reqs/vpnsrv1.req user@ip_RootCA:/tmp# scp ~/easyrsa/pki/reqs/dumasti.req user@ip_SubCA:/tmp
Переходим на сервер RootCA и подписываем сертификат. Для подписания сертификата для сервера используем атрибут server, для клиента client:
# cd ~/easyrsa/# ./easyrsa import-req /tmp/vpnsrv1.req vpnsrv1# ./easyrsa sign-req server vpnsrv1
Будет запрошено подтверждение, надо ввести yes.
# scp ~/easyrsa/pki/issued/vpnsrv1.crt user@ip_OpenVPN:/tmp# scp ~/easyrsa/pki/ca.crt user@ip_OpenVPN:/tmp/RootCA.crt
Переходим на сервер SubCA и подписываем сертификат:
# cd ~/easyrsa/# ./easyrsa import-req /tmp/dumasti.req dumasti# ./easyrsa sign-req client dumasti
Будет запрошено подтверждение, надо ввести yes.
# scp ~/easyrsa/pki/issued/dumasti.crt user@ip_OpenVPN:/tmp# scp ~/easyrsa/pki/ca.crt user@ip_OpenVPN:/tmp/SubCA.crt
Возвращаемся на сервер OpenVPN и переносим подписанные сертификаты в нужные директории:
# cd /tmp
Для того, чтобы сервер OpenVPN принял клиентские ключи, мы должны объединить в один файл открытые ключи клиента и подчиненного/подписывающего ЦС:
# cat dumasti.crt SubCA.crt > ~/client-configs/keys/dumasti.crt# cp /tmp/RootCA.crt ~/client-configs/keys/ca.crt# sudo mv /tmp/RootCA.crt /etc/openvpn/vpnsrv1/# sudo mv /tmp/vpnsrv1.crt /etc/openvpn/vpnsrv1/
Теперь у нас есть все необходимые сертификаты в нужных местах. Осталось создать конфигурацию сервера OpenVPN и клиента (у каждого могут быть свои убеждения и взгляды в данном вопросе, но для примера тут будет следующая конфигурация).
Можно использовать шаблон конфигурации сервера и клиента и отредактировать под себя:
# sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/# sudo gzip -d /etc/openvpn/server.conf.gz# cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
Но ниже я приведу содержимое уже готовых файлов конфигурации (символы; и # комментируют строку):
# sudo cat /etc/openvpn/vpnsrv1.confport 1194proto udpdev tunca vpnsrv1/RootCA.crtcert vpnsrv1/vpnsrv1.crtkey vpnsrv1/vpnsrv1.keydh vpnsrv1/dh.pemserver 10.8.0.0 255.255.255.0ifconfig-pool-persist ipp.txt;push "route 192.168.10.0 255.255.255.0";push "route 192.168.20.0 255.255.255.0";client-config-dir ccd;client-config-dir ccdpush "redirect-gateway def1 bypass-dhcp"push "dhcp-option DNS 208.67.222.222"push "dhcp-option DNS 208.67.220.220"client-to-client;duplicate-cnkeepalive 10 120tls-auth vpnsrv1/ta.key 0key-direction 0cipher AES-256-CBCauth SHA256max-clients 100user nobodygroup nogrouppersist-keypersist-tunstatus /var/log/openvpn/openvpn-status.loglog-append /var/log/openvpn/openvpn.logverb 3;mute 20explicit-exit-notify 1# cat ~/client-configs/base.confclientdev tunproto udpremote your_server_ip 1194;remote my-server-2 1194;remote-randomresolv-retry infinitenobinduser nobodygroup nogrouppersist-keypersist-tunremote-cert-tls server;tls-auth ta.key 1cipher AES-256-CBCauth SHA256key-direction 1verb 3;mute 20# script-security 2# up /etc/openvpn/update-resolv-conf# down /etc/openvpn/update-resolv-conf
Так же нам надо настроит файервол и пересылку пакетов. Можно настроить iptables, но тут мы рассмотрим ufw.
Для начала узнаем имя нашего интерфейса:
# ip addr
Откроем следующие порты (у меня ssh на 22 порту, а openvpn на 1194, если у вас другие, то действуйте соответственно):
# sudo ufw allow 1194# sudo ufw allow 22
Далее откройте файл конфигурации ufw и вставьте туда следующее перед началом цепочки filter (замените мои значения на свои):
# sudo vim /etc/ufw/before.rules# START OPENVPN RULES# NAT table rules*nat:POSTROUTING ACCEPT [0:0]# Allow traffic from OpenVPN client to eth0 (change to the interface you discovered!)-A POSTROUTING -s 10.8.0.0/8 -o ens192 -j MASQUERADECOMMIT# END OPENVPN RULES
Перед этим:
# Don't delete these required lines, otherwise there will be errors*filter
Нужно разрешить UFW пересылку пакетов по умолчанию. Находим нужную строку и меняем значение DROP на ACCEPT:
# sudo vim /etc/default/ufwDEFAULT_FORWARD_POLICY="ACCEPT"
Настраиваем пересылку пакетов. Находим строку #net.ipv4.ip_forward=0 или #net.ipv4.ip_forward=1, удалим #, если стоит значение 0, то меняем его на 1:
# sudo vim /etc/sysctl.confnet.ipv4.ip_forward=1# sudo sysctl -p# sudo ufw enable
Далее запускаем наш VPN:
# sudo systemctl start openvpn@vpnsrv1
Проверяем запуск:
# ip addr
Должен появиться новый сетевой интерфейс tun0 с ip 10.8.0.1
# sudo systemctl status openvpn@vpnsrv1
Если надо, чтобы VPN стартовал самостоятельно после перезагрузки добавляем службу в автозапуск:
# sudo systemctl enable openvpn@vpnsrv1
Далее создаем конфигурацию клиента. Ранее мы поместили все ключи и сертификаты в директорию ~/client-configs/keys/.
Создадим скрипт, который соберет конфигурацию, ключи и сертификаты в один файл user.ovpn:
# cd ~/client-configs/# vim configs-maker.sh#!/bin/bash# First argument: Client identifierKEY_DIR=/home/dumasti/client-configs/keysOUTPUT_DIR=/home/dumasti/client-configs/filesBASE_CONFIG=/home/dumasti/client-configs/base.confcat ${BASE_CONFIG} \<(echo -e '<ca>') \${KEY_DIR}/ca.crt \<(echo -e '</ca>\n<cert>') \${KEY_DIR}/${1}.crt \<(echo -e '</cert>\n<key>') \${KEY_DIR}/${1}.key \<(echo -e '</key>\n<tls-auth>') \${KEY_DIR}/ta.key \<(echo -e '</tls-auth>') \> ${OUTPUT_DIR}/${1}.ovpn
Данный скрипт будет брать файлы с именем, которое вы ему передадите во время запуска и сконфигурирует один файл в директорию files.
Сделаем файл исполняемым:
# chmod +x configs-maker.sh
Запустим его:
# sudo ./configs-maker.sh dumasti
Теперь переносим клиентскую конфигурацию на свой компьютер из директории /home/dumasti/client-configs/files/
Запускаем VPN.
Из соображений безопасности сервера, на которых стоят ЦС, должны быть выключены и включаются только для подписания сертификатов.
Не обойдем вниманием и отзыв сертификатов. Для того, чтобы отозвать сертификат мы идем на сервер ЦС на котором был подписан сертификат и выполняем следующее (Для примера мы отзовем пользовательский сертификат (dumasti), который мы подписывали на сервере SubCA). Идем на сервер SubCA:
# cd ~/easyrsa/# ./easyrsa revoke dumasti
Будет запрошено подтверждение отзыва, вводим yes
# ./easyrsa gen-crl
Был сформирован файл crl.pem. Его нам надо поместить на сервер OpenVPN и в конфигурации сервера добавить директиву и путь к файлу:
# scp ~/easyrsa/pki/crl.pem user@ip_OpenVPN:/tmp
Переходим на сервер OpenVPN:
# sudo mv /tmp/crl.pem /etc/openvpn/vpnsrv1/# sudo vim /etc/openvpn/vpnsrv1.conf
Там где прописаны ключи и сертификаты добавляем следующую строку:
crl-verify vpnsrv1/crl.pem
Перезапускаем openvpn:
# sudo systemctl restart openvpn@vpnsrv1
Теперь клиент dumasti не сможет подключиться к VPN.
Благодарю за внимание!