С недавних пор заинтересовал меня вопрос, как можно попадать в свою домашнюю сеть из большого Интернета. Нет, конечно, проброшенные ssh и rdp-порты выручают, но всё-таки это как-то неизящно. Есть, правда, ещё pptp, он он, говорят, небезопасный... В общем, захотелось что-нибудь посолиднее, и выбор пал на OpenVPN.
Сама установка трудностей не представляет:
sudo apt install openvpnОсновная интрига - как этот самый openvpn-сервер сконфигурировать. В сети полно инструкций, как это сделать с использованием easy-rsa, но на поверку оказалось, что этот самый easy-rsa - просто набор bash-скриптов для работы с openssl, так что особого смысла в использовании этой дополнительной прослойки я не увидел и насоздавал ключи и сертификаты прямо с использованием openssl.
Делается это в два присеста. Во-первых, организуется удостоверяющий центр, и, во-вторых, создаются и с его помощью подписываются сертификаты для сервера и для клиента. В результате образуется следующая структура:
Удостоверяющий центр: -- приватный ключ УЦ (бережно хранится и никому не показывается) -- сертификат УЦ (раздаётся всем кому попало) эта пара используется для подписи сертификатов сервера и клиента Сервер OpenVPN: -- сертификат УЦ -- приватный ключ сервера (бережно хранится и никому не показывается) -- сертификат сервера, подписанный УЦ (передаётся клиентам при установлении подключения) Клиент, подключающийся к серверу: -- сертификат УЦ -- приватный ключ клиента (бережно хранится и никому не показывается) -- сертификат клиента, подписанный УЦ (передаётся серверу при установлении подключения)При подключении клиент и сервер обмениваются своими сертификатами. Сервер проверяет, что сертификат клиента подписан тем же УЦ, что и его собственный, а клиент делает такую же проверку с сертификатом сервера. Если оба сертификата прошли проверку, соединение устанавливается, сервер вытаскивает из сертификата клиента ComnmonName и использует его для идентификации клиента.
Создание удостоверяющего центра (УЦ)
Можно, конечно, использовать сторонние УЦ, но там, как правило, за работу требуют денежку. Поэтому логично поднять свой УЦ. Фактически, весь УЦ - это пара файлов, ключ и самоподписанный сертификат. Единственная тонкость - из соображений безопасности эту пару файлов желательно запрятать поглубже: вынести в docker, на отдельную машину, отправить на Луну... Так или иначе, создаются эти файлы следующим образом.
1. Создаём приватный ключ УЦ:
openssl genrsa -des3 -out huhmuh-CA.key 2048
Поскольку тут фигурирует опция "-des3", то ключ будет зашифрован, поэтому потребуется ввести пароль. В дальнейшем этот пароль потребуется вводить при использовании этого ключа, например, при подписывании сертификатов, так что пароль лучше сделать помудрёнее и не забыть.
2. Создаём самоподписанный сертификат УЦ:
openssl req \ -x509 \ -days 3650 \ -key huhmuh-CA.key \ -out huhmuh-CA.crt \ -subj "/emailAddress=huhmuh@example.com/C=RU/ST=Oblastnaya oblast/L=Default City/O=Home/OU=Living room/CN=example.com" \ -addext "subjectAltName = DNS:example.com"
Можно "-subj" и не указывать, тогда при создании сертификата потребуется ответить на кучку вопросов, кто вы и откуда. Ну, и, поскольку используется huhmuh-CA.key, программа спросит для него пароль.
В результате этих манипуляций у нас на руках окажутся два файла, huhmuh-CA.key и huhmuh-CA.crt - это и будет наш удостоверяющий центр.
Создание сертификата сервера
1. Создаём приватный ключ сервера:
openssl genrsa -out huhmuh-openvpn.key 2048
Этот ключ получается незашифрованным. Наверно, это не очень хорошо, но дело в том, что сервер openvpn будет этот ключ активно использовать, и для того, чтобы ему рассказать пароль, потребуются дополнительные телодвижения. Так что в данном случае победила лень.
2. Создаём запрос сертификата для сервера:
openssl req \ -new \ -key huhmuh-openvpn.key \ -out huhmuh-openvpn.csr \ -subj "/emailAddress=huhmuh@example.com/C=RU/ST=Oblastnaya oblast/L=Default City/O=Home/OU=Living room/CN=server"
Тут стоит обратить внимание на поле /CN=server. Его значение отличается от соответствующего поля, использовавшегося при создании сертификата УЦ. Если эти поля совпадают, то клиенты почему-то считают сертификат сервера самоподписанным, насколько я понял. Поэтому лучше CommonName сертификатов УЦ и сервера сделать различными, во избежание недоразумений.
3. Подписываем сертификат в удостоверяющем центре:
Как выяснилось в процессе эксплуатации, некоторые клиенты openvpn, в частности, 2.3, требуют, чтобы сертификат содержал расширения x509v3, в которых было бы явно указано, для чего его можно использовать. Делается это при помощи следующих расширений: keyUsage и extendedKeyUsage. Можно было бы их указывать на этапе создания запроса сертификата, но почему-то на этапе подписания они теряются. Но есть положительный момент: при подписании можно добавить нужные расширения. И момент отрицательный: соответствующий параметр командной строки "-addext" срабатывает только в openssl начиная с версии 1.1.1а.
Поэтому создадим на УЦ два файла с расширениями для серверных и клиентских сертификатов.
Файл server-extensions.txt:
[default] keyUsage = digitalSignature,keyAgreement extendedKeyUsage = serverAuth
Файл client-extensions.txt:
[default] keyUsage = digitalSignature,keyAgreement extendedKeyUsage = clientAuth
И будем их использовать при подписании.
Сам процесс подписания прост: передаём на Луну файл *.csr, подписываем его в УЦ командой:
openssl x509 \ -req \ -days 3650 \ -in huhmuh-openvpn.csr \ -out huhmuh-openvpn.crt \ -CA huhmuh-CA.crt \ -CAkey huhmuh-CA.key \ -CAcreateserial \ -extfile server-extensions.txt
И возвращаем готовый сертификат huhmuh-openvpn.crt с Луны обратно на сервер, где будет жить OpenVPN.
4. Дальше потребуется сгенерировать ещё два файла, они нужны при настройке сервера. Эти файлы создаются так:
Создаём файл с параметрами для протокола Диффи-Хеллмана:
openssl dhparam -out dh.pem 2048
Создаём приватный ключ для tls-аутентификации:
openvpn --genkey --secret ta.key
Тут интересно, что используется не команда openssl, а сама программа openvpn. У этой самой openvpn оказалось вообще много всяких параметров командной строки, посмотреть их можно командой openvpn --help. Программа живёт в каталоге /sbin или /usr/sbin, эти каталоги в $PATH простых смертных не прописаны, так что если вызывать её из-под непривилегированного пользователя, возможно потребуется указать полный путь: /sbin/openvpn.
Итак, по завершении этого этапа, в нашем распоряжении будут файлы:
huhmuh-CA.crt huhmuh-openvpn.key huhmuh-openvpn.crt dh.pem ta.key
Эти файлы потребуется сгрузить в каталог /etc/openvpn, туда же скопировать из /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz образец конфигурации, распаковать его командой
gunzip server.conf.gz
При этом получится файл server.conf, и этот файл уже можно править под свои нужды.
Файл server.conf богат на комментарии, между ними запрятаны настройки, которые должны быть примерно такими:
# тут можно указать, какой адрес использовать, # но, поскольку мой сервер находится "в глубине" сети, # то у него один адрес, поэтому я оставил эту настройку закомментированной ;local a.b.c.d # порт по умолчанию 1194, но можно и сменить port 32194 # протокол рекомендуют udp, но пусть уж так proto tcp dev tun # наши ключи и сертификаты ca huhmuh-CA.crt cert huhmuh-openvpn.crt key huhmuh-openvpn.key # This file should be kept secret dh dh.pem tls-auth ta.key 0 topology subnet # задаём, какой диапазон адресов будет использоваться клиентскими подключениями # первый адрес, 10.8.0.1, сервер openvpn заберёт себе server 10.8.0.0 255.255.255.0 # логи и прочая полезная информация. # в частности, в ipp.txt показываются сопоставления CN клиентских сертификатов и выделенные для них адреса ifconfig-pool-persist /var/log/openvpn/ipp.txt status /var/log/openvpn/openvpn-status.log log-append /var/log/openvpn/openvpn.log # насколько подробным будет лог verb 6 # с этой опцией клиент будет вынужден весь свой трафик завернуть через openvpn push "redirect-gateway def1 bypass-dhcp" keepalive 10 120 # версия 2.3 знает лишь AES-256-CBC, с версии 2.4 лучше применять AES-256-GCM, он надёжнее, говорят ;cipher AES-256-CBC cipher AES-256-GCM comp-lzo # чтобы сервер не работал под рутом - для пущей безопасности user nobody group nogroup persist-key persist-tun
С готовым файлом конфигурации можно попытаться, наконец, взлететь. Под убунтой это делается командой:
systemctl start openvpn@server
Вот это дополнение, @server, задаёт имя файла конфигурации, который будет использован, т.е., server.conf. Если же взлететь с первого раза не получилось, может выручить запуск сервера командой:
openvpn --config /etc/openvpn/server.conf
И медитация над логами из /var/log/openvpn/ в попытке разобраться, что же пошло не так...
Создание файла подключения клиента
Если сервер, наконец, удалось каким-то чудом запустить, пришло время для клиента. Все настройки клиента - и конфигурация, и ключ, и сертификаты - удобно сливаются в единый файл *.ovpn.
1. Создаём приватный ключ клиента:
openssl genrsa -des3 -out huhmuh-alice.key 2048
Ключ шифруем (опция "-des3") - пусть клиент при установлении подключения вводит пароль.
2. Создаём запрос сертификата для клиента:
openssl req \ -new \ -key huhmuh-alice.key \ -out huhmuh-alice.csr \ -subj "/emailAddress=alice@example.com/C=RU/ST=Oblastnaya oblast/L=Default City/O=Home/OU=Kitchen/CN=alice"
3. Подписываем сертификат клиента в удостоверяющем центре:
openssl x509 \ -req \ -days 3650 \ -in huhmuh-alice.csr \ -out huhmuh-alice.crt \ -CA huhmuh-CA.crt \ -CAkey huhmuh-CA.key \ -CAcreateserial \ -extfile client-extensions.txt
В итоге для клиентского подключения мы приготовили файлы:
huhmuh-CA.crt huhmuh-alice.key huhmuh-alice.crt
Из этих файлов и файла /etc/openvpn/ta.key можно собрать файл подключения. Проще всего это сделать примерно таким скриптом:
#!/bin/sh FNAME=huhmuh-alice.ovpn echo "client dev tun proto tcp remote example.com 32194 resolv-retry infinite remote-cert-tls server auth SHA1 cipher AES-256-GCM tls-client key-direction 1 persist-key persist-tun resolv-retry infinite nobind comp-lzo verb 3" > $FNAME echo "<ca>" >> $FNAME cat ./huhmuh-CA.crt >> $FNAME echo "</ca>" >> $FNAME echo "<cert>" >> $FNAME cat ./huhmuh-alice.crt >> $FNAME echo "</cert>" >> $FNAME echo "<key>" >> $FNAME cat ./huhmuh-alice.key >> $FNAME echo "</key>" >> $FNAME echo "<tls-auth>" >> $FNAME cat /etc/openvpn/ta.key >> $FNAME echo "</tls-auth>" >> $FNAME
Тут надо помнить пару моментов. Во-первых, /etc/openvpn/ta.key - секретный (хотя как секретный, клиенту же передаётся?), поэтому доступен лишь под рутом. И, во-вторых, соответствующие настройки должны совпадать с настройками сервера. Например, если в конфиге сервера стоит "cipher AES-256-CBC", то и у клиента должно быть то же самое, "cipher AES-256-CBC". Про "remote example.com 32194", думаю, упоминать смысла нет - и так понятно, что это адрес сервера и открытый на нем порт.
Если всё прошло нормально, то в нашем распоряжении оказывается файл huhmuh-alice.ovpn, который можно отдавать клиенту, чтобы он с ним подключался к нашему серверу. Клиентов для OpenVPN хватает, даже под андроидом есть некий OpenVPN Connect, так что тип операционной системы использование этого инструмента не лимитирует.
(NB: для WindowsXP, как оказалось, последняя версия клиента: 2.3.18. При её настройке из скопированного в C:\Program Files\OpenVPN\config файла .ovpn пришлось удалить строку set CLIENT_CERT 0. Также эта версия начала кочевряжиться при отсутствии Key Usage в расширениях серверного сертификата, о чем было упомянуто выше. Помогает либо добавление требуемого расширения, либо убирание строки remote-cert-tls server в файле *.ovpn)
Настройка netfilter на сервере
В случае успеха клиенты, подключенные к серверу, смогут добраться лишь до этого самого сервера. Попытка попасть на какие-то другие хосты в локальной сети окажется неудачной. Для того, чтобы клиенты получили возможность пройти дальше сервера, требуется использовать nat. В принципе, можно сконфигурировать openvpn так, чтобы он позволил своим клиентам получать адреса из диапазона локальной сети. Но, поскольку в вышеприведенной конфигурации клиенты получают адреса из диапазона 10.8.0.0/24, а остальная сеть живёт в диапазоне 192.168.0.0/24, то в данном случае придётся воспользоваться iptables. Минимальная конфигурация, позволяющая это осуществить, выглядит так:
#!/bin/sh # подключаем nf_conntrack и разрешаем проброс пакетов modprobe nf_conntrack sysctl net.ipv4.ip_forward=1 # очищаем таблицы nat и filter iptables -F -t nat iptables -F -t filter iptables -X -t nat iptables -X -t filter # разрешаем работать исходящим и уже установленным подключениям iptables -t filter -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -t filter -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -t filter -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT # разрешаем доступ к серверу по перечисленным портам (не один же openvpn у нас тут крутится) iptables -t filter -A INPUT -p tcp -m multiport --dports 22,67,68,80,443,32194 -j ACCEPT iptables -t filter -A INPUT -p udp -m multiport --dports 67,68 -j ACCEPT # 22 -ssh, 67 - dhcp, 80,443 - https, 32194 - openvpn # в трафик из подсети 10.8.0.0/24 подставляем адрес сервера в локальной сети, 192.168.0.2, в качестве источника iptables -t filter -A FORWARD -s 10.8.0.0/24 -j ACCEPT iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j SNAT --to-source 192.168.0.2 # остальные пакеты, не прошедшие правила, отбрасываем (кроме исходящих) iptables -t filter -P INPUT DROP iptables -t filter -P FORWARD DROP iptables -t filter -P OUTPUT ACCEPT
Настройка клиента на ubuntu
Подключение к серверу с использованием имеющегося файла huhmuh-alice.ovpn выглядит так:
sudo openvpn --config ./huhmuh-alice.ovpn
При этом, если на сервере прописана опция redirect-gateway, весь трафик пойдёт через этот vpn-канал. Иногда это не очень удобно - например, мы сидим в большом инете и хотим подцепться к корпоративной сети, но при этом не желаем, чтобы развлекательные сайты заворачивались через служебную прокси. Это решается следующим образом.
Оказывается, в openvpn есть две внутренние константы, vpn_gateway и net_gateway. Они содержат адрес vpn-шлюза и шлюза локальной сети соответственно, и с их помощью можно задавать нужные маршруты. В файл *.ovpn добавляем строку:
route 192.168.0.0 255.255.255.0 vpn_gateway
Клиента запускаем командой:
sudo openvpn --pull-filter ignore redirect-gateway --config ./huhmuh-alice.ovpn
И весь трафик будет ходить по-старому, за исключением сети 192.168.0.0/24 - общение с ней пойдёт через vpn.
Литература
Установка и настройка OpenVPN-сервера в Debian
Конспект по установке OpenVPN
Установка и настройка сервера OpenVPN в Ubuntu 20.04
OpenSSL Quick Reference Guide
Create SSL certificate non-interactively
Генерирование сертификатов для OpenVPN с помощью Easy-RSA 3
x509v3_config
OpenVPN Certificate does not have key usage extension
OpenSSL CA keyUsage extension
IX509ExtensionEnhancedKeyUsage interface (certenroll.h)
Class ExtendedKeyUsage
Connecting to Access Server with Linux
Ignoring redirect-gateway
Комментариев нет:
Отправить комментарий