IPv6 /64 subnet szétosztása konténerekre

Adott egy host /64 IPv6 alhálózattal, amiben szeretnék IPv6-only LXC konténereket indítani, ugyanabból az alhálózatból kiosztva a címeket. Megörökíteném a későbbiekre a számomra legegyszerűbbnek tűnő megoldást. Egy Hetzner VPS-en kísérletezgetés közben szedegettem össze a lentieket, ott egyszerűen reprodukálható a folyamat.

Először is megnézzük, milyen global unicast címet kaptunk a szolgáltatótól. Esetünkben pl. a Hetzner csak /64-et ad a szervereihez, ezért amennyire én tudom, a klasszikus, routeolt megoldások sajnos nem jöhetnek szóba.

# ip addr
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 96:00:01:30:21:24 brd ff:ff:ff:ff:ff:ff
    inet6 2a01:4f9:c011:3bf::1/64 scope global 

Tehát az alhálózatunk a 2a01:4f9:c011:3bf::/64, és ebből az első címet a host fizikai interfésze kapja. Itt egy kicsit át kell konfigurálni az interfészt a routing miatt, a /64 subnetet módosítani kell /128-ra. Ez egy fontos lépés, enélkül nem fog (így) működni. Ubuntu 20.04 alatt a netplan konfigjához kell nyúlni a /128 miatt:

# cat /etc/netplan/50-cloud-init.yaml 
network:
    version: 2
    ethernets:
        eth0:
            addresses:
            - 2a01:4f9:c011:3bf::1/128
            dhcp4: true
            gateway6: fe80::1
            match:
                macaddress: '96:00:01:30:21:24'
            nameservers:
                addresses:
                - 2a01:4ff:ff00::add:2
                - 2a01:4ff:ff00::add:1
            set-name: eth0

Az /etc/sysctl.conf-ban pedig be kell kapcsolnunk az NDP proxy és forwarding paramétert:

net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.proxy_ndp=1

Restart után jöhetnek a konténerek. Itt most Ubuntu/LXD-t használunk.

Ha van a hoston tűzfal, akkor pl. UFW esetében:

IPV6=yes
DEFAULT_FORWARD_POLICY="ACCEPT"

Az LXD telepítésénél csak annyi a különlegesség, hogy lxdbr0 bridge eszközt kell használnunk egy olyan IPv6 címmel, ami ugyanazon az alhálózaton van, mint a host interfész. A ::1 volt a host, a ::2 lesz az LXD bridge. Csak a network beállításokat mutatom:

# apt install lxd (4.0 snap track)
# lxd init
Would you like to create a new local network bridge? (yes/no) [default=yes]: 
What should the new bridge be called? [default=lxdbr0]: 
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 2a01:4f9:c011:3bf::2/64
Would you like LXD to NAT IPv6 traffic on your bridge? [default=yes]: no
Would you like the LXD server to be available over the network? (yes/no) [default=no]: 

Mivel unprivileged konténereket csinálunk, létrehozzuk a usert, akinek a nevében futnak majd a konténerek:

# useradd -m demo
# adduser demo lxd

Belépünk ezzel a userrel, és megnézzük a jelenlegi LXD network beállításokat (a továbbiakban nem kell a hoston root hozzáférés):

$ lxc network show lxdbr0 
config:
  ipv4.address: 10.231.120.1/24
  ipv4.nat: "true"
  ipv6.address: 2a01:4f9:c011:3bf::2/64
  ipv6.nat: "false"
description: ""
name: lxdbr0
type: bridge
used_by:
- /1.0/profiles/default
managed: true
status: Created
locations:
- none

Még fel kell vennünk két beállítást a bridge-hez - a NAT-ot nem kértük az LXD init során, mert most tiszta IPv6 a cél:

$ lxc network set lxdbr0 ipv6.dhcp    false
$ lxc network set lxdbr0 ipv6.routing true

Az lxc network show lxdbr0 parancs már ezeket is fogja mutatni.

Jöhetnek a konténerek, csináljunk többfélét:

$ lxc launch images:ubuntu/20.04 demolxc01
$ lxc launch images:alpine/edge  demolxc02
$ lxc launch images:debian/11    demolxc03

A konténerekben pedig nem kell semmi extrát beállítani, se radvd/dhcpd6 a hoston, se macvlan az LXD-ben, csak a fentiek.

$ lxc list
+-----------+---------+-----------------------+---------------------------------------------+-----------+-----------+
|   NAME    |  STATE  |         IPV4          |                    IPV6                     |   TYPE    | SNAPSHOTS |
+-----------+---------+-----------------------+---------------------------------------------+-----------+-----------+
| demolxc01 | RUNNING | 10.231.120.123 (eth0) | 2a01:4f9:c011:3bf:216:3eff:fe7d:9734 (eth0) | CONTAINER | 0         |
+-----------+---------+-----------------------+---------------------------------------------+-----------+-----------+
| demolxc02 | RUNNING | 10.231.120.140 (eth0) | 2a01:4f9:c011:3bf:216:3eff:feb5:ddd3 (eth0) | CONTAINER | 0         |
+-----------+---------+-----------------------+---------------------------------------------+-----------+-----------+
| demolxc03 | RUNNING | 10.231.120.217 (eth0) | 2a01:4f9:c011:3bf:216:3eff:fe5a:b5d (eth0)  | CONTAINER | 0         |
+-----------+---------+-----------------------+---------------------------------------------+-----------+-----------+

A konténerek rögtön elérhetőek kívülről az IPv6 címeiken, pingre válaszolnak stb. Az IPv6 címek a konténerek MAC címéből generálódnak, amit egyébként az LXD-ben statikussá lehet tenni.

Ha valaki nem játszott még LXD konténerekkel, és ki szeretné próbálni, az "lxc exec <konténernév> bash" paranccsal be lehet lépni a hostról konténeres hálózat nélkül is, be lehet állítani SSH-t, tűzfalat stb.

Források: 

https://ipv6-first-guide.hillbrecht.de
https://blogs.infoblox.com/ipv6-coe/fe80-1-is-a-perfectly-valid-ipv6-default-gateway-address/
https://ubuntu.com/blog/lxd-networking-lxdbr0-explained
https://discuss.linuxcontainers.org/t/getting-universally-routable-ipv6-addresses-for-your-linux-containers-on-ubuntu-18-04-with-lxd-4-0-on-a-vps/7322
https://discuss.linuxcontainers.org/t/how-to-make-lxd-give-public-ipv6-addresses-to-containers/11602

Hozzászólások

koszi, erdekes megkozelites ez is.  masik lehetoseg, ha csinalsz "brouter"-t (v4 router+v6 bridge), vagy csak siman a hostot is berakod a bridge-be.

nekem 1db v6 cimem volt az egesz hostra (servergarden), az lxc vm-jeim meg kulon v4 subnetekben mentek (hogy egymast se lassak). igy maradt a local v6 subnetek osztasa aztan v6 nat-olas :(

A szolgáltatótól miért nem kértél IPv6 prefixet? Elzárkóztak tőle, technikailag nem volt lehetséges, vagy valami olyan költségtétele lett volna, amit nem lehetett felvállalni?

Azért kérdezem, mert a szolgáltatók az egyes szolgáltatás-csomagjaikat úgy alakítják ki, hogy az az átlagjúzer átlagfeladatára jó legyen, és ha te olyat akarsz csinálni, amivel nem kalkuláltak, akkor lehet, hogy egy egyszerű kérés elegendő a probléma megoldásához. Az IPv6 prefix olcsó, sőt, egy /64 vagy /56 szinte ingyen van. Csodálkoznék, ha komoly pénzeket akarnának kérni érte.

kertem ipv6 tartomanyt, erre adtak 1db static cimet, azon is gondolkoztak 1 hetig. server hosting amugy, ipv4-ert is komoly penzeket kertek cimenkent...  mivel egyelore csak tesztelesre kellett, eleg volt az 1 is.

egyebkent amikor korulneztem par honapja a magyar server hosting / vps szolgaltatoknal, a nagy tobbsege csak 1-1 v6 cimet ad (vagy azt se), nehany ad /64-et es talan 1 volt csak aki nagyobbat.  meglepo modon kulfoldon se sokkal jobb a helyzet, tobb nagy szolgaltato valaszolta azt hogy naluk nincs ipv6. de olyan is volt aki ad /48-at, szoval eleg nagy a szoras.

IPv4 egyre drágább, mert nagyjából elfogyott.

IPv6 szerintem kb. mindenhol ingyen van. Rackforest /56-ot ad, AWS VPC is /56, Hetzner-nél a default a /64, de egyszeri 15 EUR-ért ad /56-ot (csak fizikai gépekhez).

Ha egy mód van rá, én már új projekteknél csak IPv6-ot használok, és ahol nagyon kell (pl. webes rendszereknél), ott a Cloudflare beforgatja az IPv4 látogatókat.

igen vegtelen sok v6 cim van, de olyan bokezuen szorjak, hogy ilyen tempoban az is el fog fogyni 10 even belul :)

1-1 isp kap /32-t, abbol ha 56-ot ad minden ugyfelenek eleg hamar elfogynanak, felteve hogy nem egy garazsceg par 100 ugyfellel (de azok nem is kapnak /32-t csak /48-at)

Amikor elkezdtem ismerkedni IPv6-tal, én is pontosan így gondoltam. A legnagyobb hülyeségnek tartottam, hogy a legkisebb subnet az a /64, mi a búbánatnak osztunk ki 18.446.744.073.709.551.616 db címet egy alhálózatba, ahol adott esetben csak néhány tucat végpont lesz. De így lehet minden szutyok eszköznek, sőt minden vhostnak, minden alkalmazásnak külön címe anélkül, hogy mindenféle trükköket kellene alkalmazni. 

Ha egy ISP /32-t kap, abban konkrétan annyi /64 méretű subnet van, ahány címből áll az egész IPv4 internet (hiszen az is 32 biten leírható). Ha pedig "csak" /56-ot oszt ki mindenkinek, akkor is lehet 134 millió ügyfele. 

Elég lesz.

Egyébként ha valaki RIPE tag, ott tényleg /32 az alap, de /29-et is lehet kérni, még csak megindokolni sem kell.

Ha már RIPE, a 4.2 alfejezeteit célszerű elolvani: https://www.ripe.net/publications/docs/ripe-690
Sajnos egyelőre örüljön egyetlen /64-nek. Még sokmindennek ki kell alakulnia ahhoz, hogy ezt a RIPE ajánlást tudják tartani a szolgáltatók. Szándék és technikai oldalról egyaránt.

nem egy garazsceg par 100 ugyfellel

Jah, tipikusan minden hosting szolgáltatónak több tízmillió ügyfele van :)

Ha pedig véletlen tényleg több tízmillió ügyfele van, akkor már rég igényelt a /32 helyett/mellé további tartományokat.
 

Ha pedig véletlen tényleg több tízmillió ügyfele van, akkor már rég igényelt a /32 helyett/mellé további tartományokat.

Vagy /32-nél szélesebbet igényel, ha tényleg olyan nagy és nem egy átlagos kis szolgáltató.
DIGI Tavkozlesi es Szolgaltato Kft.  /29-et igényelt. Abból szórja szét a magyar előfizetőinek az IPv6-ot, egyelőre még csak /64 prefix delegációval.

"igen vegtelen sok v6 cim van, de olyan bokezuen szorjak, hogy ilyen tempoban az is el fog fogyni 10 even belul :)"

Óhh erről egy régi kollégám posztulátuma jut eszembe. :) Neki voltak ilyenjei, amiről tudtad, hogy nem lehet igaz, de mikor kérte hogy cáfold meg, valahogy baromi nehéz volt.

Ő úgy mondta:

"Az IPv6 már elfogyott. Csak senki nem vette észre, mert igazán senki nem használja."

Félig igaza volt. Az IPv6 top level /3-as subneteknél 8-ból 3 van használva (0, 2, e), úgyhogy nem fogyott el (van még pár dobásunk, ha ezt elcsesszük). Viszont a 2-vel kezdődő publikus címtartomány szinte teljesen szét van már dobva a RIR-eknek. Aztán, hogy az egyes regionális blokkok mennyire telítettek, az jó kérdés.

Régóta vágyok én, az androidok mezonkincsére már!

Az IPv4 lassan drágább, mint a heroin. Ne keverd bele, itt konkrétan IPv6-ról volt szó.

a nagy tobbsege csak 1-1 v6 cimet ad

Mondom: feltételezem, főként azért, mert arra gondol, hogy az neked úgy jó. Merj kérni többet! Konkrétan, úgy kérj, hogy "kérek egy /64-et", vagy "kérek egy /56-ot".

Dockernél régebben (mikor még foglalkoztam vele), az volt a javaslat, hogy egy /80-as tartományt jelölj ki a konténereknek. Gondolom, hogy a 48-bites virtuális interfész MAC címeket 1:1 be tudja mappelni az IPv6-os cím suffixbe. De emlékeim szerint simán ment sokkal kisebb tartománnyal is.

Ahogy elnézem itt is valami hasonló magic van a háttérben. A konténerek címei gyanúsan mind

2a01:4f9:c011:3bf:216:3eff:fe00::/104

prefixet használnak. Viszont a konfigban csak

2a01:4f9:c011:3bf::/64

kerül említésre. Vajon honnan jön a 216:3eff:fe? Konfigurálva van, vagy random választotta magának?

Régóta vágyok én, az androidok mezonkincsére már!

Ez a SLAAC, stateless Address Auto-configuration.

pl. a konténer MAC címe: 00:16:3e:7d:97:34

Beteszünk a közepére egy FF:FE-t: 00:16:3e:ff:fe:7d:97:34

Ezt átírjuk IPv6-szerű formába: 0016:3eff:fe7d:9734

A hetedik bitet átfordítjuk, 00-ból lesz 02: 0216:3eff:fe7d:9734

Ez lesz a /64-en belül a prefix után a cím host része. 2a01:04f9:c011:03bf:0216:3eff:fe7d:9734

Itt gyönyörűen le van írva az egész, érthető ábrákkal:

https://www.networkacademy.io/ccna/ipv6/stateless-address-autoconfigura…

Sajnos ez a vendor prefix az LXD esetében nem "igazi", az OUI adatbázis szerint a 00:16:3e prefix a Xen-é, de ezt használja más virtualizációs/konténeres megoldás is. Hivatalosan az első octet utolsó előtti bitjével kellene jelölni, hogy lokál adminisztrálású MAC cím, és nem globálisan egyedi. De sajnos valamiért az LXD nem így csinálja, és nem is kért magának saját tartományt.

De igazából majdnem mindegy, mert az IPv6 prefix része úgyis egyedi lesz, úgyhogy mögötte nem gond, ha a cím host részét véletlenül egy olyan MAC címből generáljuk, ami egy másik szerveren is létezik.