Konfigurationsbeispiele für 6 Tunnel und zwei Bridges auf den 3 Endpoints, um für jeden endpoint zwei separate ethernet ports des masters als bridge zu mehreren endpoints zu brücken. Der master stellt dabei proaktiv ssh verbindungen zu den endpoints her und tunnelt somit das tap an die gemeinsame bridge. auf den endpoints wiederum wird das tap und ebenso zusammen mit der jeweiligen nic auf die gewünschte dortige bridge aufgelegt.
Ich setze für dieses Howto voraus, dass dir die daemontools und auch envdir bereits bekannt sind.
Das System ist invers konzipiert und kann z.B. innerhalb weitere NAT ssh tunnels gepackt werden, die bereits zuvor aktiv von der Gegenseite zu einem Vermittlungsserver aufgebaut wurden. Sinn und Zweck ist, dass die Endpoints über keine geheimen Schlüssel verfügen müssen und der Master selbst jederzeit Endpoints aussperren kann.
master: server (192.168.111.1) kein sshd aktiv, keine ports nach außen offen. Hardware hat nur NIC1
ep1: endpoint01 (192.168.111.11) sshd aktiv. Hardware hat NIC1, NIC2, NIC3
ep2: endpoint02 (192.168.111.12) sshd aktiv. Hardware hat NIC1, NIC2, NIC3
ep3: endpoint03 (192.168.111.13) sshd aktiv. Hardware hat NIC1, NIC2, NIC3
..
ep9: endpoint20 (192.168.111.19) sshd aktiv. Hardware hat NIC1, NIC2, NIC3
nic1: an switch hauptnetz (WAN)
nic2: an switch dediziert gebridgtes Netzwerk A (internal)
nic3: an switch dediziert gebridgtes Netzwerk B (guest)
auf der Serverseite muss in der /etc/ssh/sshd_config das hier gesetzt sein
GatewayPorts yes
idealerweise arbeitest du hierbei auf serverseite mit relativ gesymlinkten daemontool servicenames und envdir, um ein gemeinsames masterscript und tunnelscript zu nutzen und dich nicht zu wiederholen. Konrekt... Nutze auf deinem master server als root das folgende setup:
apt-get install daemontools daemontools-run
mkdir -p /srv/tunnelservice/log/
mkdir -p /srv/tunnelservice/tunnelservice0/config
mkdir -p /srv/tunnelservice/tunnelservice1/config
mkdir -p /srv/tunnelservice/tunnelservice2/config
mkdir -p /srv/tunnelservice/tunnelservice3/config
mkdir -p /srv/tunnelservice/tunnelservice4/config
mkdir -p /srv/tunnelservice/tunnelservice5/config
mkdir -p /srv/tunnelservice/tunnelservice6/config
cat << +++EOF+++ > /srv/tunnelservice/master_run
#!/bin/sh
exec 2>&1
sleep 2
test -d ./config || exit 1
test -f ../tunnelscript || exit 1
exec envdir ./config/ ../tunnelscript
+++EOF+++
cat << +++EOF+++ > /srv/tunnelservice/log/run
#!/bin/sh
exec 2>&1
exec logger -t "$(pwd)"
+++EOF+++
chmod +x /srv/tunnelservice/master_run
chmod +x /srv/tunnelservice/log/run
ln -s ../master_run /srv/tunnelservice/tunnelservice0/run
ln -s ../master_run /srv/tunnelservice/tunnelservice1/run
ln -s ../master_run /srv/tunnelservice/tunnelservice2/run
ln -s ../master_run /srv/tunnelservice/tunnelservice3/run
ln -s ../master_run /srv/tunnelservice/tunnelservice4/run
ln -s ../master_run /srv/tunnelservice/tunnelservice5/run
ln -s ../master_run /srv/tunnelservice/tunnelservice6/run
ln -s ../log/ /srv/tunnelservice/tunnelservice0/log
ln -s ../log/ /srv/tunnelservice/tunnelservice1/log
ln -s ../log/ /srv/tunnelservice/tunnelservice2/log
ln -s ../log/ /srv/tunnelservice/tunnelservice3/log
ln -s ../log/ /srv/tunnelservice/tunnelservice4/log
ln -s ../log/ /srv/tunnelservice/tunnelservice5/log
ln -s ../log/ /srv/tunnelservice/tunnelservice6/log
# services starten
ln -s /srv/tunnelservice/tunnelservice0 /etc/service/
ln -s /srv/tunnelservice/tunnelservice1 /etc/service/
ln -s /srv/tunnelservice/tunnelservice2 /etc/service/
ln -s /srv/tunnelservice/tunnelservice3 /etc/service/
ln -s /srv/tunnelservice/tunnelservice4 /etc/service/
ln -s /srv/tunnelservice/tunnelservice5 /etc/service/
ln -s /srv/tunnelservice/tunnelservice6 /etc/service/
wobei das eigentliche /srv/tunnelservice/tunnelscript dann so aus sieht
#!/bin/sh
# reinhard@finalmedia.de
exec 2>&1
ip tuntap add tap${local_tap_id} mode tap
brctl addbr br${bridge_id}
brctl addif br${bridge_id} tap{local_tap_id}
ip link set tap${local_tap_id} up
ip link set br${bridge_id} up
ip addr add ${local_bridge_ip_and_netmask} dev br0
exec ssh -C -N -o Tunnel=ethernet \
-c "chacha20-poly1305@openssh.com" \
-m "hmac-sha2-512" \
-o KexAlgorithms="curve25519-sha256" \
-o HostKeyAlgorithms="ssh-ed25519" \
-o ServerAliveInterval=10 \
-w ${local_tap_id}:${remote_tap_id} \
-i /root/.ssh/id_ed25519 \
root@${endpoint}
Beachte: Das Script setzt einen existierenden ssh privatekey voraus, hier in /root/.ssh/id_ed25519. Ich nehme also bereits an, dass du diesen mit
ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -C "tunnelmaster"
erzeugt hast und den zugehörigen publickey /root/.ssh/id_ed25519.pub dann auf allen endpoint services in dortiger /root/.ssh/authorized_keys hinterlegt hast. Die Services müssen auch als root laufen, um an die taps binden zu können. Du solltest zuvor auch bereits einmal manuell eine ssh Verbindung allen endpoints aufgebaut haben, damit es einen known hosts eintrag gibt (TOFU).
In die Datei /etc/hosts auf dem Master Server die IPs der endpoints eintragen. Hier sind die IPs anzugeben, über die der masterserver alle endpoints von außen erreichen kann, um dorthin eine ssh Verbindung aufzubauen:
192.168.111.1 master
192.168.111.11 endpoint01
192.168.111.12 endpoint02
192.168.111.13 endpoint03
Hier Konfigurationsbeispiele für die env zum obigen Script, die man dann als env für die envdir configdir anlegen muss.
Jedem tunnelservice weist man dazu auch einen separaten daemontools service zu. Wir haben zwei services pro endpoint.
Pro tunnelservice hast du also je eine configdir als envdir. Gesamt also dieses setup:
echo endpoint01 > /srv/tunnelservice/tunnelservice0/config/endpoint
echo endpoint02 > /srv/tunnelservice/tunnelservice1/config/endpoint
echo endpoint03 > /srv/tunnelservice/tunnelservice2/config/endpoint
echo 192.168.90.1./24 > /srv/tunnelservice/tunnelservice0/config/local_bridge_ip_and_netmask
echo 192.168.91.1./24 > /srv/tunnelservice/tunnelservice1/config/local_bridge_ip_and_netmask
echo 192.168.90.2./24 > /srv/tunnelservice/tunnelservice2/config/local_bridge_ip_and_netmask
echo 192.168.91.2./24 > /srv/tunnelservice/tunnelservice3/config/local_bridge_ip_and_netmask
echo 192.168.90.3./24 > /srv/tunnelservice/tunnelservice4/config/local_bridge_ip_and_netmask
echo 192.168.91.3./24 > /srv/tunnelservice/tunnelservice5/config/local_bridge_ip_and_netmask
echo 0 > /srv/tunnelservice/tunnelservice0/config/bridge_id
echo 0 > /srv/tunnelservice/tunnelservice0/config/local_tap_id
echo 0 > /srv/tunnelservice/tunnelservice0/config/remote_tap_id
echo 1 > /srv/tunnelservice/tunnelservice1/config/bridge_id
echo 1 > /srv/tunnelservice/tunnelservice1/config/local_tap_id
echo 1 > /srv/tunnelservice/tunnelservice1/config/remote_tap_id
echo 0 > /srv/tunnelservice/tunnelservice2/config/bridge_id
echo 2 > /srv/tunnelservice/tunnelservice2/config/local_tap_id
echo 0 > /srv/tunnelservice/tunnelservice2/config/remote_tap_id
echo 1 > /srv/tunnelservice/tunnelservice3/config/bridge_id
echo 3 > /srv/tunnelservice/tunnelservice3/config/local_tap_id
echo 1 > /srv/tunnelservice/tunnelservice3/config/remote_tap_id
echo 0 > /srv/tunnelservice/tunnelservice4/config/bridge_id
echo 4 > /srv/tunnelservice/tunnelservice4/config/local_tap_id
echo 0 > /srv/tunnelservice/tunnelservice4/config/remote_tap_id
echo 1 > /srv/tunnelservice/tunnelservice5/config/bridge_id
echo 5 > /srv/tunnelservice/tunnelservice5/config/local_tap_id
echo 1 > /srv/tunnelservice/tunnelservice5/config/remote_tap_id
Du kannst dir im Anschluss den gesamten Config-Baum auf diese Weise ansehen:
find /srv/tunnelservice/*/config/ -type f -exec head -v -n 1 "{}"
Zusammenfassung/Listing aller Configs für dich zur Übersicht
# tunnelservice 0
bridge_id=0
local_tap_id=0
remote_tap_id=0
endpoint="endpoint01"
local_bridge_ip_and_netmask="192.168.90.1/24"
# tunnelservice 1
bridge_id=1
local_tap_id=1
remote_tap_id=1
endpoint="endpoint01"
local_bridge_ip_and_netmask="192.168.91.1/24"
# tunnelservice 2
# bindet auf endpoint02 (um an endpoint 3 das tap0 zu binden)
bridge_id=0
local_tap_id=2
remote_tap_id=0
endpoint="endpoint02"
local_bridge_ip_and_netmask="192.168.90.2/24"
# tunnelservice 3
# bindet auf endpoint02 (um an endpoint 3 das tap1 zu binden)
bridge_id=1
local_tap_id=3
remote_tap_id=1
endpoint="endpoint02"
local_bridge_ip_and_netmask="192.168.91.2/24"
# tunnelservice 4
bridge_id=0
local_tap_id=4
remote_tap_id=0
endpoint="endpoint03"
local_bridge_ip_and_netmask="192.168.90.3/24"
# tunnelservice 5
bridge_id=1
local_tap_id=5
remote_tap_id=1
endpoint="endpoint03"
local_bridge_ip_and_netmask="192.168.91.3/24"
Auf der endpoint seite, muss nur in der /root/.ssh/authorized_keys der publickey des masters hinterlegt sein, sowie in der /etc/sshd/sshd_config folgendes Setting. Damit erlauben wir nur noch ssh login als root und erlauben generell Tunnel. Auf einem Multiuser System muss das mit Match User gelöst werden. Der Endpoint sollte aber kein multiuser system sein.
AllowUsers root
PermitTunnel yes
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin prohibit-password
Die Datei /etc/network/interfaces muss dann einfach nur alle bridge und tap Regeln enthalten. Das sieht so aus beim Beispiel des endpoint01. Der Endpoint spannt einen wlan AP auf auf wlan0 und hat eine weitere nic eth1. an eth0 ist die "WAN" Seite, an die der master einen Verbindungsaufbau durchführt und seine tunnel "pushed".
# WAN eth0
auto eth0
iface eth0 inet static
address 192.168.111.11
netmask 255.255.255.0
# WLAN AP
auto wlan0
iface wlan0 inet manual
auto br0
iface br0 inet static
address 192.168.90.251
netmask 255.255.255.0
bridge_ports wlan0
post-up ip tuntap add tap0 mode tap
post-up brctl addif br0 tap0
post-up ip link set tap0 up
# LAN eth1
auto eth1
iface eth1 inet manual
auto br1
iface br1 inet static
address 192.168.91.251
netmask 255.255.255.0
bridge_ports eth1
post-up ip tuntap add tap1 mode tap
post-up brctl addif br1 tap1
post-up ip link set tap1 up
ACHTUNG: Die IP-Adressen 192.168.90.x und 192.168.91.x natürlich auf jedem endpoint anders setzen! also z.B. 251,251,253. Und auch die statische IP-Adresse der WAN Seite ist natürlich bei jedem Endpoint anders. Die 192.168.111.11 aus obigem Beispiel ist dies die IP von endpoint01! Auf dem endpoint02 würdest du 192.168.111.12 setzen.
Warum setzt du auf der master seite noch eine ip für die bridge?
Zu debugzwecken, weil man dann von der clientseite auch gut testen kann, ob eine Verbindung durch den Tunnel zur Remotebridge besteht. Es ist aber kein Muss. Wenn du reines L2 Briding machst, brauchst du das nicht zwingend. Im /srv/tunnelservice/tunnelscript auf dem master server kannst du daher die betreffende Zeile einfach mit Kommentarzeichen versehen, um sie nicht auszuführen
# ip addr add ${local_bridge_ip_and_netmask} dev br0