Лаборатория VPN в VirtualBox: шлюзовая VM или сеть только для хоста
Выберите между маршрутизируемой шлюзовой VM и сегментом только для хоста для лаборатории VPN в VirtualBox, а затем заставьте гостя отказать закрыто при падении туннеля.
Вам нужно решить, сколько техники заслуживает ваша лаборатория VPN. Маршрутизируемая шлюзовая VM между двумя сегментами VirtualBox воспроизводит трансляцию адресов, обратный путь и позицию межсетевого экрана, за которым сидит реальный клиент. Один сегмент только для хоста даёт одну контролируемую дверь и ничего больше. Вариант со шлюзом стоит три гостя и таблицу маршрутизации, которую вы поддерживаете; вариант только для хоста стоит одного гостя и одной политики. Три вопроса разделяют их, и третий решает, может ли ваш тест вообще пройти.
Ответьте на три вопроса, прежде чем что-либо клонировать
Начните с того, что должен наблюдать сервер VPN. Если сервер должен видеть адрес источника, который не принадлежит тестовому гостю, что-то должно транслировать между ними, и этим чем-то должен быть маршрутизатор, которым управляете вы. Сеть только для хоста даёт хосту адаптер в сегменте гостя, а не транслятор. Когда гостю затем нужно достичь чего-то снаружи, вы подключаете адаптер NAT, и собственный NAT-движок VirtualBox переписывает источник, не спрашивая вас.
Затем спросите, может ли гость достичь чего-либо иначе, чем через туннель. Этот ответ выбирает внутреннюю или только для хоста, и это тот вопрос, который пропускают большинство описаний лабораторий. Наконец, спросите, что должно произойти при падении туннеля, потому что это определяет политику, а не топологию, а лаборатория, доказывающая только счастливый путь, не проверила почти ничего.
| What the test requires | Routed gateway VM | Host-only guest |
|---|---|---|
| Server sees a translated source address | Yes, from your own MASQUERADE rule | No, VirtualBox NAT does it instead |
| The guest has exactly one egress | Yes, while the second adapter faces the tunnel | Only until a NAT adapter is attached |
| Policy is testable during a tunnel failure | Rules live in one place | Rules live on each guest |
Соедините три роли внутренними сетями
Используйте три гостя и два именованных сегмента, а шлюз пусть будет единственной машиной с адаптером на обоих:
VBoxManage modifyvm lab-client --nic1 intnet --intnet1 WAN
VBoxManage modifyvm lab-server --nic1 intnet --intnet1 LAN
VBoxManage modifyvm lab-gw --nic1 intnet --intnet1 WAN --nic2 intnet --intnet2 LAN
Отдельного шага создания для внутренней сети нет. Строка в --intnet1 и есть сегмент: две машины делят его, только если имя совпадает точно, и ничто на хосте к нему не подключено. Именно это последнее свойство и делает лабораторию чисто повторяемой, потому что маршруты хоста, его собственный клиент VPN и его межсетевой экран не могут случайно добраться до гостей. У внутреннего сегмента также нет DHCP-сервера, если вы его не добавите, поэтому статические адреса — самый короткий путь.
Дайте клиенту только его WAN-адрес, а шлюз по умолчанию должен указывать на WAN-адрес шлюза. Сервер получает LAN-адрес и использует LAN-адрес шлюза как свой шлюз по умолчанию. У гостя, который держит два адреса на одном сегменте или имеет заблудший маршрут в другой сегмент, есть путь в обход маршрутизатора, и тесты ниже будут вам лгать.
Я держу текстовый файл рядом с именами VM с четырьмя адресами и двумя именами сегментов и вставляю его в каждую оболочку. Недели спустя, когда изменение профиля что-то ломает, этот файл — разница между отладкой профиля и отладкой собственной памяти.
Выберите внутренний или только для хоста для сегмента, который не должен протекать
Режим только для хоста создаёт виртуальный адаптер на самом хосте, обычно vboxnet0, и даёт хосту адрес в сегменте гостя. Это удобно для администрирования и губительно для теста изоляции, потому что хост теперь может достичь гостя напрямую, и каждая служба на стороне хоста становится возможным путём. У внутреннего режима вообще нет адаптера хоста. Два режима легко перепутать в панели настроек сети, поэтому проверяйте документированное различие, а не ярлык (смотрите страницу подробности о сети VirtualBox).
Для гостя, которому обязательно нужен туннель, внутренний режим — более безопасное значение по умолчанию, а шлюз — единственный выход. Если вы оставляете только для хоста, относитесь к адаптеру хоста как к пути управления и скажите это вслух: хост может достичь гостя, а гость не должен иметь возможности использовать хост как выход.
VBoxManage modifyvm lab-client --nic1 hostonly --hostonlyadapter1 vboxnet0
Изоляция, которую вы можете доказать, — это изоляция, которую вы настроили. У гостя с одним внутренним адаптером, маршрутом по умолчанию на шлюзе и без адаптера NAT нет пути в обход шлюза. У гостя с адаптером только для хоста и адаптером NAT есть два пути, и только один из них — тот, который вы хотели проверить.
Маршрутизируйте и транслируйте на шлюзе, а затем заставьте его отказать закрыто
VirtualBox не пересылает между сегментами; это делает гость. Когда VM сервера VPN стоит за шлюзом, включите пересылку и транслируйте трафик клиента, когда он уходит к серверу:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
С этим правилом сервер видит LAN-адрес шлюза вместо адреса клиента, и именно так реальный клиент за NAT оператора выглядит для головного узла сети. Сохраните значение sysctl в /etc/sysctl.d/, а правило — в той службе межсетевого экрана, которую использует дистрибутив, иначе перезагрузка тихо вернёт лабораторию в маршрутизированное, но нетранслированное состояние.
Пересылка — это не авторизация. При политике FORWARD по умолчанию со значением ACCEPT гость, чей маршрут по умолчанию указывает на шлюз, выходит через тот интерфейс, который выберет таблица маршрутизации, с туннелем или без. Если у шлюза есть ещё и адаптер NAT для установки пакетов, этот адаптер — работающий незашифрованный выход в тот момент, когда туннель падает, и ваш тест «только VPN» никогда не был тестом «только VPN».
Когда сервер удалён, а туннель завершает сам шлюз, то же решение указывает на интерфейс туннеля, а не на сетевую карту, которая выходит в интернет:
iptables -P FORWARD DROP
iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
Держите собственный внешний транспорт туннеля и внеполосный маршрут управления отдельно от пересылаемого трафика. Если единственный способ починить шлюз — через туннель, который вы отлаживаете, лаборатория превращается в упражнение по блокировке. Последовательная консоль, адаптер управления только для хоста или снимок известного хорошего состояния дешевле, чем ручное восстановление сломанного маршрутизатора.
Проверяйте путь со стороны гостя, а не хоста
Работайте наружу. Убедитесь, что клиент достигает WAN-адреса шлюза, затем сервера через шлюз, затем что соединение к порту VPN уходит и возвращается. Запись на обоих интерфейсах шлюза показывает, приходит ли ответ и отбрасывается ли он на обратном пути, чего запись только на клиенте различить не может:
tcpdump -ni eth0 udp port 1194
tcpdump -ni tun0 udp port 1194
Затем докажите выход. Спросите из гостя службу отражения адресов, какой источник она видит, и сравните с собственным выходным адресом шлюза; если ответ совпадает с адресом хоста, путь в обход туннеля существует. Проверьте, какой распознаватель гость действительно использует, и проверьте IPv6 отдельно, потому что сегмент, где IPv6 включён, а туннель несёт только IPv4, протекает по замыслу, а не случайно.
Наконец, сломайте это намеренно. Остановите туннель или заблокируйте его внешний порт и откройте новое соединение из гостя. Оно должно не удаться, и причина должна быть такой, которую вы можете назвать: нет маршрута, есть правило отклонения или распознаватель мёртв. Перезапустите туннель и убедитесь, что гость восстанавливается без перестройки сети. Если mesh VPN вроде Hamachi или ZeroTier делит лабораторию, помните, что мостовой адаптер следует за именем адаптера, а не за mesh, поэтому мост нужно перенаправить после того, как клиент установит свой собственный виртуальный адаптер.
VBoxManage list bridgedifs
VBoxManage modifyvm lab-client --bridgeadapter1 <mesh-adapter-name>
Совместное использование туннеля гостя с хостом отражает проблему. Направить маршрут хоста по умолчанию на гостя — работает, как и прокси внутри гостя; NAT через хост не несёт туннель гостя для трафика, который начал хост. Сохраните имена сегментов и правила межсетевого экрана в одном месте, сделайте снимок работающего состояния и запишите адрес источника, который наблюдал сервер. Тогда следующее изменение профиля будет стоить одного запуска скрипта вместо перестроенной лаборатории.