Demo: Thick Jail with VNET

Problem — von ezjail auf native Jails migrieren (Hintergrund).

Mein Setup — Kind seiner Zeit und geht inzwischen besser.

Auf dieser Seite — wie kann ich (testweise) eine Thick Jail mit VNET erstellen und diese (vorerst) parallel neben ezjail laufen lassen?

Netzwerk (bisher)

Meine Jails haben das Netzwerk bisher so aufgesetzt:

/etc/rc.conf vom Host:

cloned_interfaces="lo1"
ifconfig_lo1="inet 10.13.12.1/32"
ifconfig_lo1_ipv6="inet6 fd32:10:13:12::1 prefixlen 128"

In der /usr/local/etc/ezjail/some:

export jail_some_hostname="some"
export jail_some_ip="lo1|10.13.12.3,lo1|fd32:10:13:12::3"

Und die /etc/pf.conf (grob):

# public addresses
 ip_em0_p4 = "1.2.3.4"
 ip_em0_p6 = "1234:5678:90ab:cdef::1"

# jail addresses
 ip_j_some4 = "10.13.12.3"
 ip_j_some6 = "fd32:10:13:12::3"

…

# allow loopback traffic
 set skip on { lo0, lo1 }

# outbound traffic from jails
 nat pass on em0 inet  from (lo1:network) to any -> $ip_em0_p4
 nat pass on em0 inet6 from (lo1:network) to any -> $ip_em0_p6

# redirect traffic into jails
 rdr pass log on em0 inet  proto tcp from any to (em0:network) port http  -> $ip_j_some4
 rdr pass log on em0 inet6 proto tcp from any to (em0:network) port http  -> $ip_j_some6
 rdr pass log on em0 inet  proto tcp from any to (em0:network) port https -> $ip_j_some4
 rdr pass log on em0 inet6 proto tcp from any to (em0:network) port https -> $ip_j_some6

…

Funktioniert und tut was es soll. Geht so, passt. Ist aber bisschen hämdsärmlig. vnet soll jetzt modern sein.

Storage

Die Jails von ezjail liegen unter /usr/jails, der Pool heißt tank.

Bei der Ordnerstruktur orientiere ich mich am Handbuch und erstelle mir Datasets:

zfs create tank/root/containers
zfs create tank/root/containers/classic

Schaut dann grob so aus:

…
tank                          3.15T  3.69T   128K  none
tank/root                     3.15T  3.69T   151K  /usr/jails
…
tank/root/containers           279K  3.69T   140K  /usr/jails/containers
tank/root/containers/classic   140K  3.69T   140K  /usr/jails/containers/classic
…

Thick Jail erstellen

Eigentlich geht es jetzt stumpf nach Handbuch

Einmal das Userland bitte:

fetch https://download.freebsd.org/ftp/releases/amd64/amd64/`uname -r`/base.txz \
  -o /usr/jails/containers/base.txz

Extrahieren:

tar -xf /usr/jails/containers/base.txz \
  -C /usr/jails/containers/classic --unlink

Die timezone setzen:

cp /usr/jails/containers/classic/usr/share/zoneinfo/Europe/Berlin \
  /usr/jails/containers/classic/etc/localtime

Als resolv.conf nutzen wir direkt die Server von Quad9:

cat << EOF > /usr/jails/containers/classic/etc/resolv.conf
nameserver 2620:fe::fe
nameserver 2620:fe::9

nameserver 149.112.112.112
nameserver 9.9.9.9
EOF

Haare schön machen:

freebsd-update -b /usr/jails/containers/classic fetch install

Netzwerk Config mit VNET

Die /etc/rc.conf wird erweitert:

cloned_interfaces="lo1 bridge0"
ifconfig_lo1="inet 10.13.12.1/32"
ifconfig_lo1_ipv6="inet6 fd32:10:13:12::1 prefixlen 128"
ifconfig_bridge0="inet 10.13.37.1/24"
ifconfig_bridge0_ipv6="inet6 fd32:10:13:37::1 prefixlen 64"
autobridge_interfaces="bridge0"
autobridge_bridge0="epair*a em0"

Sollte dann auch hoch kommen:

service bridge restart
service netif cloneup

Dazu in der /etc/pf.conf (grob):

…
# allow loopback traffic
 set skip on { lo0, lo1, bridge0 }

# outbound traffic from jails
…
 nat pass on em0 inet  from (bridge0:network) to any -> $ip_em0_p4
 nat pass on em0 inet6 from (bridge0:network) to any -> $ip_em0_p6

# redirect traffic into jails
…
 rdr pass log on em0 inet  proto tcp from any to (em0:network) port 4242 -> "10.13.37.23"
 rdr pass log on em0 inet6 proto tcp from any to (em0:network) port 4242 -> "fd32:10:13:37:11::17"
…

Geht erstmal darum zu testen ob Trafic aus/in die Jail kommt. Deshalb fixe IP-Adressen und Ports… Wenn Test vorbei kommt das wieder weg!

pf neustarten, sich dadurch aus der ssh Session werfen, fluchen, Tastatur & Monitor anschließen (falls geht) oder ganzen Server neustarten. Ist mir noch nie passiert…

Jail Config

Hackerman fängt schon mal hart mit Templating an. Dies hilft immer einheitlich zu bleiben. Auch wage ich den Versuch auf so Sachen wie .include "/etc/jail.conf.d/*.conf"; o.Ä. zu verzichten – Debugging wird einfacher wenn man nur ein File öffnen muss. Das Resultat: Eine handverlesene Mixtur aus den Thick & VNET Handbuch Seiten, der /var/run/jail.some.conf und der Quelle Internet…

exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
exec.system_user = "root";
exec.jail_user = "root";
exec.clean;

mount.fstab;
mount.devfs;
devfs_ruleset = 5;

path = "/usr/jails/containers/${name}";
mount.fstab = "/etc/fstab.jail.${name}";

allow.raw_sockets;
host.hostname = "${name}";

vnet;
vnet.interface = "${epair}b";

exec.prestart  = "/sbin/ifconfig ${epair} create up";
exec.prestart += "/sbin/ifconfig ${epair}a descr jail=${name} up";
exec.prestart += "/sbin/ifconfig ${bridge} addm ${epair}a up";
exec.start += "/sbin/ifconfig ${epair}b inet ${ipv4} up";
exec.start += "/sbin/ifconfig ${epair}b inet6 ${ipv6} up";
exec.start += "/sbin/route -4 add default ${gw_4}";
exec.start += "/sbin/route -6 add default ${gw_6}";
exec.poststop += "/sbin/ifconfig ${bridge} deletem ${epair}a";
exec.poststop += "/sbin/ifconfig ${epair}a destroy";

classic {
    $num = "23";
    $hex = "17";
}

* {
    $ipv4 = "10.13.37.${num}/24";
    $ipv6 = "fd32:10:13:37:11::${hex}/64";
    $gw_4 = "10.13.37.1";
    $gw_6 = "fd32:10:13:37::1";
    $epair = "epair${num}";
    $bridge = "bridge0";
}

Pro Jail muss man nur $num und $hex definieren, Netzwerk Config in einer Wildcard, ganz oben einheitliche Config. So der Plan…

  • exec.consolelog = "/var/log/jail_console_${name}.log";

    • ezjail macht /var/log/jail_${name}_console.log
    • somit wird neu/alt nicht clashen.
  • devfs_ruleset = 5; muss das vnet ruleset sein..

    • Das Default in /etc/defaults/devfs.rules ist 5:
      • [devfsrules_jail_vnet=5]
  • mount.fstab = "/etc/fstab.jail.${name}";

    • ezjail macht /etc/fstab.${name}
    • somit wird neu/alt nicht clashen.
    • Wird erst für Thin Jails relevant
    • Es reicht echo "#" > /etc/fstab.jail.classic
  • vnet; & vnet.interface = "${epair}b";

    • Ist das Ziel der ganzen Aktion
    • Für die Jail classic wäre das epair23b
  • exec.prestart (Auf dem Host)

    • Interfaces epair23a & epair23b werden erstellt
    • epair23a wird member der bridge0
  • exec.start (In der Jail)

    • epair23b bekommt IPv4 & IPv6 Addressen gesetzt
    • default routen werden gesetzt

Starten

Eigentlich haben wir alles die Jail sollte hoch kommen:

service jail onestart classic

In ezjail-admin list taucht classic nicht auf, jedoch in jls:

   JID  IP Address      Hostname                      Path
     …
     5  10.13.12.3      some                          /usr/jails/some
     …
    10                  classic                       /usr/jails/containers/classic

IP-Addresse hier nicht dabei! 🙀 Danke, VNET!

ifconfig zeigt epair23a und bridge0 hat dies als Member…

Testen

In die Jail kommt man stumpf mit jexec classic, oder vornehmer mit jexec classic login -f root (motd, “You have mail.”).

Wir sollten die Devices /dev/zfs & /dev/pf (wegen: devfs_ruleset = 5;) sehen.

Netzwerk geht?

drill aaaa wissen.der-beweis.de
drill a wissen.der-beweis.de
ping -6 -c 3 wissen.der-beweis.de
ping -c 3 wissen.der-beweis.de

;; ANSWER SECTION: & 0.0% packet loss ist das was wir sehen wollen! \o/

Wir haben Verbindung nach draußen.

Dann mal anders rum: nc -l 4242

Und von außen auf den Server: nc fetter.server.example.net 4242

Kryptische Nachricht erscheint. Also funktioniert auch! \o/

Fazit

Läuft!

Seitdem eine /etc/jail.conf existiert, wird pro einzelner ezjail die startet eine neue Warning ausgegeben:

WARNING: /var/run/jail.some.conf is created and used for jail some.
…
/etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables  is obsolete.
  Please consider migrating to /etc/jail.conf.

Letzte Nachricht ist ja bereits bekannt - Was meinst du warum ich gerade den ganzen Aufwand treibe? 😅

Auch dauert das starten der Jails von ezjail jetzt gefühlt länger, aber es funktioniert alles weiterhin.

ezjail parallel mit jail funktioniert auch:

sysrc ezjail_enable=YES ; sysrc jail_enable=YES
  • service ezjail restart startet nur die eigenen Jails neu.
  • service jail restart stoppt alle Jails, aber hängt bei ezjail die mountpoints nicht korrekt aus…

Also besser die Jails immer einzeln mit dem richtigen Tool neu starten.

  • Jetzt funktionieren auch service jail console classic & service jail console some.
    • Macht aber less kaputt
      • WARNING: terminal is not fully functional
      • wtf?

Was fehlt:

  • Nur /etc/resolv.conf & /etc/localtime haben wir angefasst..
    • Irgendwas wie ezjail flavor nachbauen?
      • sysrc sendmail_enable=NONE oder ähnliche Späße laufen lassen..

Und weiter?

¯\_(ツ)_/¯

last update: 2024-12-19 19:16:54 +0100