Gdy NetBSD na chwilę zostaje hubem IPsec dla innych sieci zza Cisco ASA

Splot okoliczności sprawił, że mój domowy router na NetBSD musiał na chwilę zostać centralnym hubem IPsec dla trzech oddziałów wpiętych w Cisco ASA. Bez sięgania po wysłużonego racoona, za to ze strongSwanem. Pokazuję konfigurację po obu stronach i pułapki, które mnie po drodze ugryzły.

Gdy NetBSD na chwilę zostaje hubem IPsec dla innych sieci zza Cisco ASA
Photo by D koi / Unsplash

Bywa tak, że splot okoliczności wsadza ci na biurko zadanie, którego się nie spodziewałeś. U mnie wyglądało to mniej więcej tak: trzy oddziały, każdy spięty po IPsec tak, jak Pan Bóg przykazał - na Cisco ASA i porządnych core'owych switchach. Działało jak w zegarku. Tyle że z powodów zupełnie nieistotnych dla tego wpisu te trzy lokalizacje musiały przez pewien czas „spotykać się" u mnie. W domu. W homelabie.

A mój homelab - mimo wielu prób, eksperymentów i dobrych chęci — nadal stoi na NetBSD z pf. Nie npf, nie OPNsense, nie żaden inny modny kombajn z webUI. Po prostu NetBSD. Próbowałem nowszych rzeczy parę razy i za każdym razem wracałem, bo do mojego use case'u nic nie pasuje lepiej: przewidywalne, lekkie, nudne w najlepszym tego słowa znaczeniu. pf.conf mieści mi się w głowie i nie budzę się w nocy z pytaniem „co tam znowu się mogło wywalić".

XCY Mini PC bez wentylatora Intel Core i5 i7 i3 4. i 5. generacji, 2x Serial RS232, 2x GbE, HDMI, VGA, 4x porty USB, obsługa WiFi, Windows, Linux
Smarter Shopping, Better Living! Aliexpress.com

No i nagle ten spokojny router domowy ma na chwilę zostać centralnym hubem IPsec dla trzech sieci wpiętych w Cisco ASA. Czas nagli. I rodzi się pytanie: jak to w ogóle ugryźć?

„Na czym to postawić" — czyli ucieczka od racoona

Pierwszy odruch NetBSD-owca: w base systemie jest przecież racoon z ipsec-tools i setkey do ręcznego klepania SPD/SAD. Tyle że racoon to IKEv1, projekt od lat praktycznie martwy, a konfiguracja pod interop z Cisco potrafi zamienić popołudnie w sesję spirytystyczną. Przy presji czasu to ostatnie, czego chcę.

Krótkie drążenie tematu i proszę: nie trzeba jechać na starym racoonie z base systemu. Jest nowoczesne, żywe rozwiązanie - strongSwan - i jest świetnie kompatybilne z tym, co robi Cisco.

Czym właściwie jest strongSwan

Mała dygresja historyczna, bo projekt ma ciekawy rodowód. Wszystko zaczęło się od FreeS/WAN (koniec lat 90., pierwsza poważna implementacja IPsec dla Linuksa, firmowana m.in. przez Johna Gilmore'a). Z FreeS/WAN około 2004 roku wyrosły dwa forki: Openswan i właśnie strongSwan, prowadzony przez zespół Andreasa Steffena na ówczesnej HSR w Szwajcarii.

strongSwan poszedł mocno w stronę IKEv2 (RFC 7296), certyfikatów X.509, EAP i nowoczesnej kryptografii i w tym jest dziś jednym z najdojrzalszych dostępnych rozwiązań. Działa nie tylko na Linuksie, ale też na *BSD czy macOS (no w sumie to też BSD). Ciekawostka: wbudowany klient IPsec VPN w Androidzie bazuje właśnie na strongSwanie, więc nosicie go w kieszeni, nawet o tym nie wiedząc.

Dla nas najważniejsze jest jedno: strongSwan dogaduje się z Cisco ASA bez tańca z bębnem. IKEv1 i IKEv2, PSK i certyfikaty, NAT-T, DPD - wszystko, czego ASA oczekuje od „normalnego" peera site-to-site.

Topologia (adresacja wygenerowana, nie sprawdzajcie :)

Żeby było konkretnie, ale bez zdradzania czegokolwiek z prawdziwej sieci - cała reszta wpisu operuje na adresach z pul dokumentacyjnych (RFC 5737 / RFC 1918):

                 NetBSD hub (homelab)
                 WAN: 203.0.113.10
                 chroniona sieć huba: 10.10.0.0/16
                       |
       ┌───────────────┼───────────────┐
       │               │               │
   Oddział A        Oddział B        Oddział C
   ASA 198.51.100.20  ASA ...x.21    ASA ...x.22
   LAN 10.20.0.0/16  10.30.0.0/16   10.40.0.0/16

Klasyczny hub-and-spoke: każdy oddział buduje tunel do huba, a za hubem siedzą zasoby w 10.10.0.0/16. Poniżej pokazuję konfigurację dla jednego oddziału (A); pozostałe to kopia z podmienionym adresem peera i podsiecią.

Strona Cisco ASA (IKEv2, site-to-site, PSK)

Nic egzotycznego — czysty IKEv2 z kluczem współdzielonym:

! --- IKEv2 (faza 1) ---
crypto ikev2 policy 10
 encryption aes-256
 integrity sha256
 group 14
 prf sha256
 lifetime seconds 28800
crypto ikev2 enable outside

! --- propozycja IPsec (faza 2) ---
crypto ipsec ikev2 ipsec-proposal AES256-SHA256
 protocol esp encryption aes-256
 protocol esp integrity sha-256

! --- peer + PSK ---
tunnel-group 203.0.113.10 type ipsec-l2l
tunnel-group 203.0.113.10 ipsec-attributes
 ikev2 remote-authentication pre-shared-key TutajTwojBardzoDlugiPSK
 ikev2 local-authentication  pre-shared-key TutajTwojBardzoDlugiPSK

! --- "interesting traffic" = traffic selectors ---
access-list VPN-HUB extended permit ip 10.20.0.0 255.255.0.0 10.10.0.0 255.255.0.0

crypto map OUTSIDE-MAP 10 match address VPN-HUB
crypto map OUTSIDE-MAP 10 set peer 203.0.113.10
crypto map OUTSIDE-MAP 10 set ikev2 ipsec-proposal AES256-SHA256
crypto map OUTSIDE-MAP 10 set pfs group14
crypto map OUTSIDE-MAP interface outside

Lokalna podsieć ASA to 10.20.0.0/16, zdalna (za hubem) to 10.10.0.0/16 — to one zdefiniują traffic selectory, które po stronie NetBSD muszą się idealnie pokryć (tylko „na krzyż").

Kabel konsolowy USB C 3.1 do RJ45 FTDI Chip Serial Wire RS232 do routera Cisco RJ 45 Konwerter Switch Line Przedłużacze typu C - AliExpress 44
Smarter Shopping, Better Living! Aliexpress.com

Strona NetBSD - instalacja strongSwana

strongSwan siedzi w pkgsrc-wip (wip/strongswan), więc budujemy z drzewa:

cd /usr/pkgsrc/wip/strongswan
make install clean clean-depends

Włączamy forwarding (router musi przepuszczać pakiety między interfejsami, ale przy NetBSD jako router to na pewno jest włączone) :

sysctl -w net.inet.ip.forwarding=1
# na stałe:
echo "net.inet.ip.forwarding=1" >> /etc/sysctl.conf

Tu drobna, ale ważna BSD-owa uwaga: na Linuksie strongSwan rozmawia z jądrem przez kernel-netlink. Na NetBSD korzysta z kernel-pfkey (PF_KEY do zarządzania SA) i kernel-pfroute (tablica routingu). To domyślne wtyczki demona charon w buildzie BSD-owym i zwykle nie trzeba nic ruszać , ale warto wiedzieć, czego szukać w logach, gdyby coś nie wstawało.

Strona NetBSD - konfiguracja (swanctl)

Nowoczesny strongSwan konfigurujemy przez swanctl.conf (interfejs vici), a nie przez wysłużone ipsec.conf. Plik trafia zwykle do /usr/pkg/etc/swanctl/swanctl.conf:

connections {
    oddzial-a {
        version = 2
        local_addrs  = 203.0.113.10
        remote_addrs = 198.51.100.20

        local {
            auth = psk
            id   = 203.0.113.10
        }
        remote {
            auth = psk
            id   = 198.51.100.20
        }

        children {
            oddzial-a {
                local_ts  = 10.10.0.0/16
                remote_ts = 10.20.0.0/16
                esp_proposals = aes256-sha256-modp2048
                start_action  = trap
                dpd_action    = restart
            }
        }

        proposals = aes256-sha256-modp2048
    }
}

secrets {
    ike-oddzial-a {
        id     = 198.51.100.20
        secret = "TutajTwojBardzoDlugiPSK"
    }
}

Zwróćcie uwagę na symetrię z konfiguracją ASA:

  • proposals = faza 1 (IKE): AES-256 / SHA-256 / DH group 14 (modp2048),
  • esp_proposals = faza 2 (ESP): to samo + modp2048, bo na ASA włączyłem pfs group14,
  • local_ts/remote_ts to dokładnie odwrócone ACL-e z crypto mapy ASA.

Jeśli wolicie zostać przy klasycznym ipsec.conf (stroke) — strongSwan nadal to wspiera, ale do nowych wdrożeń swanctl jest właściwą drogą.

NetBSD - pf, loopback i trasy

Trzy rzeczy, o których łatwo zapomnieć, a bez których tunel albo nie wstanie, albo wstanie i „nic nie jeździ".

1. pf musi przepuścić IKE i ESP na WAN-ie:

ext_if = "wm0"

pass in  on $ext_if proto udp from any to ($ext_if) port { 500, 4500 }
pass in  on $ext_if proto esp from any to ($ext_if)
pass out on $ext_if proto esp from ($ext_if) to any

2. Loopback alias, żeby sam hub żył w chronionej sieci. Jeśli chcecie, żeby usługi na samym routerze (albo jego własne pakiety wpuszczane do tunelu) miały adres ze wspólnej puli, wygodnie dać aliasa na lo0:

ifconfig lo0 alias 10.10.0.1 netmask 255.255.255.255

Dzięki temu hub ma „swój" adres w 10.10.0.0/16 i może np. odpytywać hosty w oddziałach z właściwym źródłem (które łapie się w traffic selectory tunelu).

3. Trasy do zdalnych podsieci. Przy IPsec policy-based to jądrowy SPD decyduje, co szyfrować, ale router i tak musi wiedzieć, że pakiet do 10.20.0.0/16 ma w ogóle ruszyć w stronę WAN-u:

route add -net 10.20.0.0/16 203.0.113.10

Uruchomienie i weryfikacja

# wczytaj konfigurację i sekrety
swanctl --load-all

# zainicjuj tunel (albo poczekaj aż 'trap' złapie pierwszy pakiet)
swanctl --initiate --child oddzial-a

# sprawdź stan
swanctl --list-sas

W --list-sas szukamy ESTABLISHED dla połączenia i INSTALLED, TUNNEL dla childa, z poprawnie wyświetlonymi selektorami 10.10.0.0/16 === 10.20.0.0/16. Na ASA dla porządku: show crypto ikev2 sa i show crypto ipsec sa.

Potem zwykły test końcowy - ping z chronionej sieci po jednej stronie do hosta po drugiej. Jeśli SA stoją, a ping nie idzie, w 90% przypadków winne są: niedopasowane traffic selectory albo firewall na samym hoście docelowym (Windows potrafi dropować ICMP, choć TCP/UDP przechodzi).

Czego się nauczyłem (czyli pułapki)

Kilka rzeczy, które oszczędzą wam siwych włosów:

  • Kryptografia musi się zgadzać po obu stronach - co do joty. Faza 1 i faza 2 osobno. Jeden „group 14" kontra „group 2" i tunel albo nie wstanie, albo wstanie i się rozjedzie.
  • Stary sprzęt Cisco bywa upośledzony kryptograficznie. Część leciwych ASA (zwłaszcza modele EoL) nie wspiera SHA-2 dla ESP sprzętowo - zostaje SHA-1, a czasem tylko DH group 2. Zanim zaczniecie debugować strongSwana, sprawdźcie, co druga strona w ogóle potrafi.
  • pf i IPsec to dwa różne światy w ścieżce pakietu. Jeśli kusi was, żeby NAT-ować jakiś ruch do tunelu (np. wpuścić inną podsieć przez istniejące SA), uważajcie na kolejność: na BSD polityka IPsec potrafi być sprawdzana, zanim pf zdąży podmienić adres źródłowy wtedy pakiet wyleci niezaszyfrowany. To temat na osobny wpis, ale zapamiętajcie sam sygnał ostrzegawczy.
  • DPD to nie luksus, tylko higiena. dpd_action = restart po stronie strongSwana sprawia, że po krótkiej awarii łącza tunel sam się podnosi, zamiast wisieć w martwym stanie.
  • Hub-and-spoke = jeden connection na oddział. Nie próbujcie upychać wielu podsieci w jeden wpis na siłę - czytelniej i pewniej jest mieć osobne połączenie per peer.

Zakończenie

To było rozwiązanie tymczasowe - docelowo te oddziały wracają do swojego naturalnego środowiska (Cisco ASA + porządny zdalny dostęp przez klienta VPN), a mój homelab z ulgą oddaje rolę huba. Ale przez ten czas zwykły domowy router na NetBSD z pf i strongSwanem udźwignął rolę centralnego węzła IPsec dla trzech lokalizacji za Cisco ASA - stabilnie, przewidywalnie i bez dramatów.

I to jest właśnie powód, dla którego ciągle tu jestem. NetBSD znów po cichu zrobiło swoje.

Listed on Blogarama·OnTopList