Каскадирование VPN-серверов

В статье приводится настройка каскадирования двух VPN серверов через Amnezia WireGuard 2.0 + клиентский OpenVPN

0. Входные данные

Сервер А:

  • Debian 13.
  • Месторасположение: «Тут»
  • OpenVPN + PKI + скрипты для управления конфигурациями пользователей. Подсеть 10.8.0.0/24
  • Клиент Amnezia Wireguard
  • Используется policy-based routing, весь трафик из подсети OpenVPN туннелируется на сервер B
  • NAT не используется
  • Внешний интерфейс eth0

Сервер B:

  • Debian 13
  • Месторасположение: «Там»
  • Сервер Amnezia Wireguard. Подсеть 192.168.100.0/30 (линковая), можно использовать 24 маску, не принципиально
  • Весь трафик, пришедший через AWG туннель из подсети OpenVPN сервера A NAT-ится во внешний интерфейс
  • Внешний интерфейс eth0

На обоих серверах необходимо разрешить IP Forwarding:

echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-forward.conf

sysctl --system

(не sysctl -p, в новых дистрибутивах ругается на отсутствующий рудимент /etc/sysctl.conf)

Проверяем. Команда cat /proc/sys/net/ipv4/ip_forward должна вернуть «1»

В статье не рассматривается настройка файрвола. Предполагается, что все политики имеют дефолтное значение ACCEPT. Также не затрагивается настройка DNS, хотя это очень важный момент (но не в рамках данной тематики).

1. Настраиваем OpenVPN на сервере A

Настройка типовая, ничего особенного.

Устанавливаем пакеты:

apt install openvpn easy-rsa

  • Создаем инфраструктуру открытых ключей (PKI)

mkdir -p /etc/openvpn/easy-rsa
cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
cd /etc/openvpn/easy-rsa
./easyrsa init-pki

  • Генерируем CA-ключ

Выполняем либо ./easyrsa build-ca — сертификат будет защищен паролем, если секьюрность не важна — можно выполнить команду ./easyrsa build-ca nopass
Утилита попросит ввести Common Name — можно вводить что угодно, либо согласиться с дефолтным значением.

  • Создаем сертификат сервера

Выполняем ./easyrsa build-server-full server nopass
По умолчанию срок действия сертификата составляет 825 дней.

  • Создаем DH

./easyrsa gen-dh

  • Создаем TLS ключ

openvpn --genkey secret ta.key

  • Находясь в директории /etc/openvpn/easy-rsa, копируем в /etc/openvpn/server ключи и сертификаты.

cp pki/ca.crt /etc/openvpn/server/
cp pki/private/server.key /etc/openvpn/server/
cp pki/issued/server.crt /etc/openvpn/server/
cp pki/dh.pem /etc/openvpn/server/
cp ta.key /etc/openvpn/server/

  • Пилим конфигурационный файл сервера /etc/openvpn/server/server.conf

port 1194
proto udp
dev tun

ca ca.crt
cert server.crt
key server.key
dh dh.pem

tls-auth ta.key 0

topology subnet

server 10.8.0.0 255.255.255.0

ifconfig-pool-persist ipp.txt

push «redirect-gateway def1 bypass-dhcp»

keepalive 10 120

persist-key
persist-tun

user nobody
group nogroup

cipher AES-256-GCM
data-ciphers AES-256-GCM:AES-128-GCM

auth SHA256

explicit-exit-notify 1

verb 3

  • Запускаем и проверяем OpenVPN сервер

systemctl enable --now openvpn-server@server
systemctl status openvpn-server@server
Должно быть active (running), а также должен появиться интерфейс tun0 с адресом 10.8.0.1/24

  • Создаем клиентов OpenVPN

Можно либо вручную сгенерировать сертификаты и ключи и сделать конфиг
Из каталога /etc/openvpn/easy-rsa запустить ./easyrsa build-client-full client1 nopass, где client1  — имя клиента
Конфиг клиента примет вид

client
dev tun
proto udp

remote <IP_СЕРВЕРА А> 1194

resolv-retry infinite
nobind

persist-key
persist-tun

remote-cert-tls server

cipher AES-256-GCM
data-ciphers AES-256-GCM:AES-128-GCM

auth SHA256

key-direction 1

verb 3

<ca>
Здесь содержимое pki/ca.crt
</ca>

<cert>
Здесь содержимое pki/issued/client1.crt
</cert>

<key>
Здесь содержимое pki/private/client1.key
</key>

<tls-auth>
Здесь содержимое ta.key
</tls-auth>

Либо можно воспользоваться скриптом

<здесь должен быть скрипт, но он gone away…>

2. Развертываем AmneziaWG

Будем собирать из исходников — DKMS-модуль и утилиты awg-tools. Можно подключить PPA репозитории от ubuntu, если не хочется возиться с сорцами. Пока выполняем на обоих серверах.

  • Ставим кухню

apt install git dkms build-essential linux-headers-$(uname -r)
cd /usr/src
git clone https://github.com/amnezia-vpn/amneziawg-linux-kernel-module.git amneziawg

  • Ставим модуль через DKMS:

cd /usr/src/amneziawg/srс
make dkms-install
dkms add -m amneziawg -v 1.0.0
dkms build -m amneziawg -v 1.0.0
dkms install -m amneziawg -v 1.0.0

  • Проверяем и загружаем модуль

dkms status должно вернуть что-то типа amneziawg/1.0.0, 6.12.95+deb13-cloud-amd64, x86_64: installed

modprobe amneziawg

lsmod | grep amneziawg должна вернуть список с модулем amneziawg и его дочерними модулями (libchacha20poly1305, udp_tunnel и прочие)

  • Ставим awg-tools

cd /usr/src/
git clone https://github.com/amnezia-vpn/amneziawg-tools.git
cd amneziawg-tools/src
make install

  • Здесь наши пути расходятся. Пилим конфиг сервера (Сервер B)

Начало ничем не отличается от классического WG — генерация пары ключей

awg genkey | tee /etc/amnezia/amneziawg/server_privatekey | awg pubkey | tee /etc/amnezia/amneziawg/server_publickey

Далее создаем /etc/amnezia/amneziawg/awg0.conf

[Interface]
PrivateKey = <Содержимое /etc/amnezia/amneziawg/server_privatekey>
Address = 192.168.100.1/30
# В принципе можно использовать любой порт
ListenPort = 39743
# Маскарадим трафик, пришедший с сети OpenVPN через внешний сетевой интерфейс
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
# Ниже параметры задают обфускацию.
Jc = 4
Jmin = 77
Jmax = 148
S1 = 72
S2 = 82
S3 = 13
S4 = 23
H1 = 686090309-771938546
H2 = 980996358-1363648663
H3 = 1371752148-1574630916
H4 = 1607849087-1706193491
I1 = <r 111>

Про параметры вкратце ниже:

Параметр Описание Диапазон Пример
Jc Количество junk-пакетов 3-6 5
Jmin Мин. размер junk (байт) 40-89 55
Jmax Макс. размер junk (байт) Jmin+50..Jmin+250 200
S1 Padding init-сообщения (байт) 15-150 72
S2 Padding response-сообщения (байт) 15-150, S1+56≠S2 56
S3 Padding cookie-сообщения (байт) 8-55 32
S4 Padding data-сообщения (байт) 4-27 16
H1 Идентификатор init-сообщения Диапазон uint32 134567-245678
H2 Идентификатор response-сообщения Диапазон uint32 3456789-4567890
H3 Идентификатор cookie-сообщения Диапазон uint32 56789012-67890123
H4 Идентификатор data-сообщения Диапазон uint32 456789012-567890123
I1 CPS concealment packet Формат <r N> <r 128>
I2I5 Доп. CPS / special-junk пакеты, опциональны Теги <r N> / <b 0xHEX> / <c> / <t> <b 0xf1>


Критические ограничения:

  • H1-H4 диапазоны не должны пересекаться.
  • S1 + 56 ≠ S2 — предотвращает одинаковый размер init и response сообщений.
  • Все узлы (сервер + клиенты) должны использовать одинаковые параметры (вплоть до регистра).

Подробно можно почитать тут https://habr.com/ru/companies/amnezia/articles/1014636/ или тут https://github.com/bivlked/amneziawg-installer/blob/main/ADVANCED.md#awg2-params-adv

Добавляем клиента. Генерим ключи:

awg genkey | tee /etc/amnezia/amneziawg/client_privatekey | awg pubkey | tee /etc/amnezia/amneziawg/client_publickey

В конец файла /etc/amnezia/amneziawg/awg0.conf добавляем секцию

# Name = Server A
[Peer]
PublicKey = <Содержимое /etc/amnezia/amneziawg/client_publickey>
# Разрешаем линковую сеть и сеть OpenVPN сервера A. Заодно пропишется обратный маршрут к подсети OpenVPN
AllowedIPs = 192.168.100.2/30, 10.8.0.0/24

  • Пилим конфиг клиента /etc/amnezia/amneziawg/awg0.conf — на сервере A

[Interface]
PrivateKey = <Содержимое /etc/amnezia/amneziawg/client_privatekey с Сервера B>
Address = 192.168.100.2/30
# В принципе можно использовать любой порт
ListenPort = 31764
# Отключаем добавление маршрутов в системные таблицы маршрутизации
Table = off
# Задаём route policy — весь трафик с сети OpenVPN загоняем в таблицу маршрутизации с номером 100
PostUp = ip route replace default via 192.168.100.1 dev awg0 table 100
PostUp = ip rule add from 10.8.0.0/24 table 100
PostDown = ip rule del from 10.8.0.0/24 table 100
# Ниже параметры задают обфускацию. Точно такие же, как на сервере A
Jc = 4
Jmin = 77
Jmax = 148
S1 = 72
S2 = 82
S3 = 13
S4 = 23
H1 = 686090309-771938546
H2 = 980996358-1363648663
H3 = 1371752148-1574630916
H4 = 1607849087-1706193491
I1 = <r 111>

[Peer]
PublicKey = <Содержимое /etc/amnezia/amneziawg/server_publickey с Сервера B>
# Разрешаем любой адрес. Чтобы не переписывался default маршрут — выше параметр Table = off
AllowedIPs = 0.0.0.0/0
Endpoint = <Адрес:порт сервера B>

  • Запуск и проверка

На обоих серверах запускаем демона
systemctl enable --now awg-quick@awg0

Должен создаться интерфейс awg0 с соответствующими IP

Пингуем сервера друг с друга по туннельным адресам — должно работать.

На сервере А (который «тут», который клиент AmneziaWG) должна создаться таблица маршрутизации 100, правило и политика маршрутизации:

ip rule show

32765: from 10.8.0.0/24 lookup 100

ip route list table 100

default via 192.168.100.1 dev awg0

На сервере B должно создаться правило NAT (можно сделать маскарадинг по-другому — «покрасить» входящий трафик с интерфейса awg0 и потом по этой маркировке сделать NAT наружу, но в данном случае это лишнее)

iptables -t nat -L

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all — 10.8.0.0/24 anywhere

или iptables-save

*nat
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Ну и маршрут должен быть в OpenVPN сеть

10.8.0.0/24 dev awg0 scope link

3. Финиш

Подключаемся OpenVPN клиентом — и «Мы оказались за кордоном. Линять надо быстро и тихо»

Для тех, кто в танке не понял как работает: клиент OpenVPN при подключении командой с сервера push «redirect-gateway def1 bypass-dhcp» переписывает дефолтный маршрут на маршрут в OpenVPN-туннель. На сервере А в соответствии с политикой маршрутизации — всё, что пришло из сети OpenVPN, попадает в таблицу 100, где присутствует маршрут по-умолчанию на сервер B через интерфейс awg0. На сервере B файрволом осуществляется NAT-ирование (маскарадинг трафика) из сети OpenVPN через внешний интерфейс.

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *