Сразу хочу отметить, что тут я больший упор делал на настройку ЦС чем на 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_EXPIRE 3650 #--> 3650
#set_var EASYRSA_CERT_EXPIRE 3650 #--> 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_EXPIRE 3650 #--> 1825
#set_var EASYRSA_CERT_EXPIRE 3650 #--> 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.conf
port 1194
proto udp
dev tun
ca vpnsrv1/RootCA.crt
cert vpnsrv1/vpnsrv1.crt
key vpnsrv1/vpnsrv1.key
dh vpnsrv1/dh.pem
server 10.8.0.0 255.255.255.0
ifconfig-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 ccd
push "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-cn
keepalive 10 120
tls-auth vpnsrv1/ta.key 0
key-direction 0
cipher AES-256-CBC
auth SHA256
max-clients 100
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3
;mute 20
explicit-exit-notify 1
# cat ~/client-configs/base.conf
client
dev tun
proto udp
remote your_server_ip 1194
;remote my-server-2 1194
;remote-random
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
;tls-auth ta.key 1
cipher AES-256-CBC
auth SHA256
key-direction 1
verb 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 MASQUERADE
COMMIT
# END OPENVPN RULES
Перед этим:
# Don't delete these required lines, otherwise there will be errors
*filter
Нужно разрешить UFW пересылку пакетов по умолчанию. Находим нужную строку и меняем значение «DROP» на «ACCEPT»:
# sudo vim /etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"
Настраиваем пересылку пакетов. Находим строку #net.ipv4.ip_forward=0 или #net.ipv4.ip_forward=1, удалим #, если стоит значение 0, то меняем его на 1:
# sudo vim /etc/sysctl.conf
net.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 identifier
KEY_DIR=/home/dumasti/client-configs/keys
OUTPUT_DIR=/home/dumasti/client-configs/files
BASE_CONFIG=/home/dumasti/client-configs/base.conf
cat ${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.
Благодарю за внимание!
AlexGluck
Почти всё тоже самое, только лучше, одним скриптом и для центос:
Переменные, которые доступны для изменения при создании впн сервера:
${STAND}
${VPN_PORT:-1194}
${VPN_PROTO:-udp}
${VPN_SUBNET:-10.254.250.0}
${VPN_DOMAIN:-vpn.alexgluck.ru}
Как поднять опенвпн сервер:
Установить OS: centos 7 minimal
Запустить на нём скрипт
Создать конфигурации для клиентов /etc/openvpn/create_new_client.sh <ИМЯ_ПОЛЬЗОВАТЕЛЯ>
Отправить конфигурации из папки /etc/openvpn/client/ пользователям
Пользоваться
Когда истечёт сертификат сервера, перевыпустить его:
export EASYRSA_VARS_FILE="/etc/openvpn/vars"
/usr/share/easy-rsa/3/easyrsa --batch renew "$KEY_NAME"
systemctl restart openvpn-server@${VPN_PROTO:-udp}
Когда истечёт СА сертификат, пересоздать впн. (Есть получше механизм, но описывать пока некогда)
andreymal
А где в этом скрипте второй ЦС и защита закрытого ключа?
AlexGluck
Второй ЦС одним скриптом делать не стоит, тут его нет, поэтому я и написал «почти тоже самое».
Sap_ru
Механизм «получше» это тупо создать новые корневой сертификат с другой датой, подписанный тем же приватным ключём, что и старый? Интересно, что это этом многие не знают — всё упорно обновляют корневые сертификаты у сотен клиентов.
AlexGluck
Вот только надо не теорию сказать, а команду дать, как это выполнить на easyrsa3, желательно проверить работоспособность.
AlexGluck
Всё равно ca у клиентов обновлять, мы же новые сертификат выпускаем ца.
dumasti Автор
Автоматизация — это конечно хорошо, сам за нее топлю, но этот скрипт написан под один сервер на котором и openvpn и ЦС. Даже не меняются права доступа, в плане безопасности это совсем печально. Но соглашусь, что этот скрипт отлично подойдет для частного использования.
AlexGluck
Он был сделан для бастион хоста, как инструкция, что делать, для понимания как в общих чертах настраивать openvpn. На работе мы просто добавили авторизацию через АД и второй фактор, помимо сертификатов. Я сейчас продвигаю иной механизм выдачи впн конфигов, сотрудники сами в веб интерфейсе должны получать свой впн конфиг. Сотрудник авторизуется на веб интерфейсе с помощью АД учётки и двухфакторки, если сотруднику разрешено пользоваться впн, ему показывает БОЛЬШУЮ кнопку скачать и инструкцию как установить и настроить впн.
dumasti Автор
Идея, чтобы сотрудники сами себе скачивали из веба клиентский сертификат хорошая, но это уже другая песня. ЦС мы ведь делаем один раз на долгий срок, а клиентские сертификаты могут штамповаться до посинения и тут скрипты, да еще и для самовыпуска через веб отлично подойдут.