Назад | Перейти на главную страницу

Wireguard как мост виртуальных машин без гипервизора, видимый в VPN

Я пытаюсь соединить два гипервизора через Интернет. Оба гипервизора используют KVM для виртуализации, и я вручную создал мосты для сети виртуальных машин, которая в настоящее время работает.

Я хотел бы использовать Wireguard для подключения мостов виртуальных машин на обоих этих гипервизорах, чтобы виртуальные машины можно было переносить с одного гипервизора на другой без каких-либо изменений маршрутизации / сети в самой виртуальной машине.

Однако перед тем, как начать, я понял, что понятия не имею, как настроить Wireguard таким образом, чтобы мосты на обоих гипервизорах являются видимый для другого гипервизора, но сами гипервизоры не появляются в VPN, так что виртуальные машины не могут напрямую подключаться / атаковать гипервизоры.

Может ли Wireguard это сделать? Или это было бы невозможно из-за того, как Wireguard работает высоко в стеке OSI, а не на уровне кадра Ethernet?

Сможет ли кто-нибудь сказать, можно ли использовать Wireguard для «слепого» соединения двух сетей? Или хосты всегда будут отображаться в сети? Может ли это позволить какое-нибудь другое решение VPN? Или мне лучше использовать брандмауэр для блокировки хостов, к которым я не хочу получать доступ?

Заранее спасибо!

Wireguard работает на уровне 3 (маршрутизируемый IP-пакет), а мост работает на уровне 2 (коммутируемый кадр Ethernet). Так что Wireguard не может этого сделать. Этот вопрос уже был задан, и автор Wireguard дал ответ в списке рассылки Wireguard: Мост wg и нормальные интерфейсы?.

Таким образом, перед прохождением проволочной защиты необходим дополнительный герметизирующий слой. Я уверен, что есть несколько вариантов (среди них VXLAN также доступно на Linux).

Я сделал пример, используя ГРЕТАП и пространства имен (а не фактические гипервизоры и виртуальные машины). Я обнаружил, что для того, чтобы не заставлять локальный трафик виртуальных машин иметь более ограниченный размер пакета, чем это возможно, необходима обработка фрагментации, но GRETAP имеет некоторые ограничения, как описано здесь: Мост GRE, IPsec и NFQUEUE. Я решил обойти это, используя искажение полезной нагрузки nftables а не NFQUEUE и пользовательское пространство.

Также обратите внимание, что RFC 6864 объясняет, что фрагментированные пакеты следует ограничивать большую часть времени до 6,4 Мбит / с из-за ограничений поля IP ID, которые в настоящее время работают медленно, но проходят через туннель с строгими проверками целостностирасслабляет его.

Здесь (поддельные) виртуальные машины связаны мостом и не имеют других возможностей подключения. Они не могут видеть ничего, кроме самих себя: они не могут видеть (поддельные) гипервизоры, соединяющие два моста с помощью gretap + wireguard. Просто запустите этот сценарий bash, который создает и настраивает несколько пространств имен. Протестировано с nftables 0.9.2 и ядром 5.2.x.

#!/bin/bash

if ip netns id | grep -qv '^ *$' ; then
    printf 'ERROR: leave netns "%s" first\n' $(ip netns id) >&2
    exit 1
fi

hosts='vm11 vm12 hyp1 router hyp2 vm21 vm22'

for ns in $hosts; do
    ip netns del $ns 2>/dev/null || :
    ip netns add $ns
    ip netns exec $ns sysctl -q -w net.ipv6.conf.default.disable_ipv6=1
    ip netns exec $ns sysctl -q -w net.ipv4.icmp_echo_ignore_broadcasts=0
done

for ns in $hosts; do
    ip -n $ns link set lo up
done

link_ns () {
    ip -n $1 link add name "$3" type veth peer netns $2 name "$4"
    ip -n $1 link set dev "$3" up
    ip -n $2 link set dev "$4" up
}

for h in 1 2; do
    ip -n hyp$h link add bridge0 address 02:00:00:00:00:0$h type bridge
    ip -n hyp$h link set bridge0 up
    for n in 1 2; do
        link_ns vm$h$n hyp$h eth0 port$n
        ip -n hyp$h link set dev port$n master bridge0
        ip -n vm$h$n address add 10.0.$h.$n/16 dev eth0
    done
    link_ns hyp$h router eth0 site$h
done

ip -n router address add 192.0.2.1/24 dev site1
ip -n router address add 198.51.100.1/24 dev site2

ip -n hyp1 address add 192.0.2.100/24 dev eth0
ip -n hyp1 route add default via 192.0.2.1

ip -n hyp2 address add 198.51.100.200/24 dev eth0
ip -n hyp2 route add default via 198.51.100.1

privkey1=$(wg genkey)
privkey2=$(wg genkey)

pubkey1=$(printf '%s' "$privkey1" | wg pubkey)
pubkey2=$(printf '%s' "$privkey2" | wg pubkey)

for h in 1 2; do
    ip -n hyp$h link add name wg0 type wireguard
    ip -n hyp$h address add 10.100.0.$h/24 dev wg0
    ip -n hyp$h link set dev wg0 up
done

ip netns exec hyp1 wg set wg0 private-key <(printf '%s' "$privkey1") listen-port 11111 peer "$pubkey2" endpoint 198.51.100.200:22222 allowed-ips 10.100.0.2
ip netns exec hyp2 wg set wg0 private-key <(printf '%s' "$privkey2") listen-port 22222 peer "$pubkey1" endpoint 192.0.2.100:11111 allowed-ips 10.100.0.1

for h in 1 2; do
    ip -n hyp$h link add name gt0 mtu 1500 type gretap remote 10.100.0.$((3-$h)) local 10.100.0.$h nopmtud
    ip -n hyp$h link set gt0 master bridge0
    ip -n hyp$h link set gt0 up
    ip netns exec hyp$h nft -f /dev/stdin << EOF
table ip filter {
    chain output {
        type filter hook output priority 0; policy accept;
        ip protocol gre ip saddr 10.100.0.$h ip daddr 10.100.0.$((3-$h)) ip frag-off set ip frag-off & 0xbfff counter
    }
}
EOF
done

Пример (с большими задержками с удаленной стороны):

# ip netns exec vm11 ping -b 10.0.255.255
WARNING: pinging broadcast address
PING 10.0.255.255 (10.0.255.255) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.194 ms (DUP!)
64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.646 ms (DUP!)
64 bytes from 10.0.2.1: icmp_seq=1 ttl=64 time=0.685 ms (DUP!)
64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.154 ms (DUP!)
64 bytes from 10.0.2.2: icmp_seq=2 ttl=64 time=0.476 ms (DUP!)
64 bytes from 10.0.2.1: icmp_seq=2 ttl=64 time=0.490 ms (DUP!)
^C
--- 10.0.255.255 ping statistics ---
2 packets transmitted, 2 received, +6 duplicates, 0% packet loss, time 1050ms
rtt min/avg/max/mdev = 0.048/0.344/0.685/0.243 ms