Tag Archives: linux

juniper ex & vmx

VMX

In lumea asta a virtualizarii, si producatorii de routere s-au apucat sa vand variantele virtuale ale produselor lor. Si cea mai simpla treaba e sa vinzi un router, ca acum in zilele noastre cu un procesor multicore poti plimba multe multe pachete dintr-o parte in alta si pana la cativa zeci de gigabiti nu ai neaparat nevoie de un ASIC dedicat pentru asta.

Din varii motive, imi place JUNOS si pe la ce clienti am mai instalat una alta, daca era si Juniper pe lista de producatori acceptati, le propuneam o solutie cu produsele lor. Din categoria oricum toata lumea pune Cisco, hai sa folosim si altceva similar.

Mno, acum cativa ani, a scos Juniper si varianta virtuala a routerelor MX pe care a botezat-o in mod foarte creativ VMX…

E. Toate bune si frumoase. Ideea la Juniper, dar cum e si la restul de producatori, presupune ca ai un “control card” si una sau mai multe “forwarding cards” si alea au ASIC-uri si ce trebuie, si control card-urile doar se ocupa de programare. Easy-peasy.

Ce-a zis Juniper: pai facem la fel, un routing engine si un line card pe care punem cate porturi o fi nevoie. Treaba cu Juniper e ca RE-ul ruleaza un FreeBSD modificat. Pentru line-card au zis ca pot folosi Linux + ceva modificari de la ei sa “mearga repede”.

Si daca vrei un router din asta virtual de la Juniper, tre sa pui doua masini virtuale: una cu FreeBSD si una cu Linux. Nu suna rau in teorie, insa in practica necesita destul de multe resurse. Da sa zicem ca iau un server dedicat pentru asta si aia e.

Din motive care insa imi scapa, Juniper s-a apucat sa foloseasca Windriver Linux, siii…. au inventat un soft care ruleaza intr-un super tight-loop care se ocupa de forwarding-ul de pachete. Si ai un sistem care e totul tipul cu CPU-urile in 100% fara absolut nici un motiv. Zici ca aia care au facut modulul vietii nu stiu ca Linux stie sa proceseze singur pachetele cat mai eficient posibil, nu trebuie sa ti-o arzi prostu cu “sunt pachete? sunt pachete? sunt pachete?” pe queue-urile de primire din kernel.

Si tot in inteligenta lor nemasurata, n-au inteles cum sa-si faca singuri update la JUNOS si daca vrei sa faci upgrade la o versiune noua procesul este interesant de simplu: faci backup la configuratie si la licente (ca logic ca e cu licenta, mai ales ca explica acolo ca e spre binele meu, cum sa nu…), reinstalezi masinile virtuale si re-aplici configuratia si licentele pe versiunea noua.

Da cred ca asta e pretul pe care-l platesti cand ai nevoie doar de 10-20Gbps de routare si nu vrei sa dai 50-60K EUR pe un router “hardware” cand poti scoate totul in 15K cu un server.

Da sa moara bibi, sa nu fii capabil sa faci doua OS-uri sa se updateze singure cu ceva gen snapshot-uri si alte nebuneli…

EX

Tot acum ceva ani, s-a apucat Juniper de facut si switch-uri, ca au auzit ei ca se saturase lumea de Cisco si vor niste switch-uri si mai scumpe. Asa s-a inventat linia de produse EX.

Anii au trecut si au evoluat si switch-urile. Si acum ai un switch care are pentru partea de control are un Linux de ruleaza niste VM-uri care contin softul care vorbeste cu ASIC-urile de pe porturile de switching. Inception modern. Teoria fiind ca atunci cand faci update de OS poti s-o faci online, doar cu o intrerupere minora de trafic. In practica nu prea merge ISSU/TISSU deloc. Dar banuiesc ca vroia si Juniper momentul lor de faima pe care l-a avut Cisco acum 20 de ani cand au inventat Online Insertion & Removal pe 7500, care invariabila rebuta routerul cand cand bagai un card nou. Si asa OIR s-a transformat in Online Insertion & Reboot. Asa si astia, 20 de ani mai tarziu nu poti face online upgrade…

In 2023 Linuxul pe care l-au pus astia pe post de OS este CentOS 6.2. Da, fix ala cu kernel 2.6.32. De nici internetul nu mai stie de el. Si astia se mai lauda ca au si divizii care fac produse de securitate…

De cretinatatea asta cu EX nu vroiam sa scriu, dar m-au scos din minti ca am incercat sa instalez versiunea de OS recomandata de ei pe site, si dupa reboot s-a pisat cu bolta pe mine qemu de pe host ca nus’ce segmente nu ajung nu stiu unde si a durat o vesnicie sa copiez versiunea anterioara de software la 10kB/s prin SCP ca stateau procesoarele in 100% ca au muit virtualizarea. Si sa copiezi aproape 700MB cu 10kB… dureaza ceva.

Cam asa mi-am petrecut un weekend din Ianuarie intr-un datacenter. Macar era mai cald acolo decat afara si am facut un pic de economie la gaze ca am oprit centrala cat am fost plecat :))

Morala povestii e ca nu trebuie avut nici un fel de increde in firme din astea care’s obisnuite sa vanda cutii sa se prieapa la lucruri un pic mai complicate gen virtualizare sau similar.

ubuntu pro rant

root@ops:~# apt upgrade
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
The following security updates require Ubuntu Pro with 'esm-apps' enabled:
  redis redis-tools redis-server
Learn more about Ubuntu Pro at https://ubuntu.com/pro
The following packages will be upgraded:
  ubuntu-advantage-tools
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 173 kB of archives.
After this operation, 3072 B of additional disk space will be used.
Do you want to continue? [Y/n] y

Azi avusei neplacuta surpriza sa fac niste lucruri pe o masina si sa aflu ca daca vreau update-uri la Redis pe Ubuntu LTS trebuie sa dau niste bani. Gen $400/an pe masina.

Si abia ce terminasem cu hatereala fata de aia de la RedHat care si-au batut joc de CentOS ca sa forteze lumea sa cumpere subscriptii de RHEL.

nereus

In ultima vreme, pe unde am apucat, am schimbat certificatele digitale folosite cu cele emise de Let’s Encrypt. Mai ales ca certbot face minuni pus in cron.

In materie de client-to-site VPN, in ultimii ani am tot bagat PaloAlto ca au un client dragut, configurare este usor de facut si merge si pe IPv6 cum trebuie, inclusiv sa aloce adrese de IPv6 pe tunel.

Problema cu asta e ca e un pic obositor la 3 luni sa uploadez de mana certificat nou, ca automat nu stie. Si pe langa asta, are o cretinatate ca vrea parola la cheia privata daca o uploadez si pe aia o data cu certificatul. Si cum certbot nu pune parole la cheile private, ar trebui sa ma dau un pic si cu OpenSSL sa ii pun parola la cheie, s-o concatenez cu certificatul si dupa sa uploadez totul.

Pe langa asta, eu tot cochetez asa sporadic cu programarea, ca e cam complicat sa faci si DevOps fara Dev :)) Ca ma mai scap sa fac si d’astea.

Anyways, long story short, zilele astea am butonat la un mic script/app (ca toate’s app-uri acum) care automatizeaza distractia asta cu Let’s Encrypt si PAN.

Asa a aparut Nereus. Scris in Python, cat se poate de curat si cat am duce pe mine acum capul sa scriu cod curat.

elasticsearch fun

Elasticsearch asta e misto sa pui chestii in el si dupa aia sa le cauti si sa le analizezi.

Mai putin distractiv e cand de la o versiune la alta nu merg lucruri si in documentatia aia a lor care e scrisa de autisti nu gasesti nimic util.

Pe undeva pe la 6.8 sau 7.0, au renuntat la ideea de a face un index pe zi. Cazul cel mai comun e cand scrie Logstash in el si indecsii se chemau logstash-2019.04.01, logstash-2019.04.02 si asa mai departe.

E, au zis ei ca nu mai e modern sa folosesti curator sa stergi indecsii vechi si l-au invatat pe Elasticsearch sa faca asta. Si nu mai e chiar ok sa ai indecsi dupa data, ci sa ii ai dupa logstash-0001, logstash-0002 si tot asa. Si Logstash sa scrie in indexul numit logstash care e de fapt un alias la logstash-xxxx, care se roteste dupa “rollover policy” – policy care poate fi setat la numar de documente, secunde (gen cat de batran e indexul) sau marime.

Pana aici, nici o problema. Problema apare cand vrei sa pui niste setari mai aparte pe index, cum ar fi numarul maxim de campuri ce pot fi mapate intr-un index. Implicit vine cu 1000 de campuri, care de fapt sunt 1002, da’ nu e important ca nici eu nu ma pricep la matematica.

“Inainte”, dupa ce faceai primul index, ii ziceai asa:

~$ curl -XPUT 'localhost:9200/logstash/_settings' -H 'Content-Type: application/json' -d'{"index":{"mapping":{"total_fields":{"limit":"2000"}}}}'

Si acum poti sa-i zici la fel, da ce sa vezi, uita de treaba asta cand roteste indexul si aplica setarile implicite. Si cum ziceam, documenatie scrisa de autisti, ca nu zice nicaeri cum sloboz sa-l faci sa fie ca inainte.

Azi, dupa ce mi-am futut intermitent creierii cu asta am gasit cum se rezolva: trebuie modificate setarile de pe template la index cam asa:

~$ curl -XPUT localhost:9200/_template/logstash -H 'Content-Type: application/json' -d '{"index_patterns":["logstash-*"],"settings":{"index":{"mapping.total_fields.limit":"2000"}}}'

Care mapping.total.fields.limit “inainte” era un parametru prin elasticsearch.yml, dar daca il pui acum, crapa ca zice ca nu mai e OK parametrul.

Distractia asta a durat super mult timp pana acum gasit termenii pe care sa-i caut pe internet sa ma duca intr-o directie cat de cat ok, si dupa a durat mai putin pana am nascut un JSON care sa fie acceptat de Elasticsearch.

Long story short:

~$ curl -X GET "localhost:9200/_template/logstash?pretty"
 {
   "logstash" : {
     "order" : 0,
     "index_patterns" : [
       "logstash-*"
     ],
     "settings" : {
       "index" : {
         "mapping" : {
           "total_fields" : {
             "limit" : "2000"
           }
         }
       }
     },
     "mappings" : { },
     "aliases" : { }
   }
 }

Da, cand n-ai de lucru, iti dau upgrade-urile de lucru…

enigmatique

Vineri ma plictisisem de prostituat pe la birou si m-am bagat si eu in seama intr-o discutie dintre niste programatori PHP-isti si Ops. In seama in sensul ca ascultam ca poate mai aflu chestii depsre una-alta.

La un moment dat s-au apucat sa vorbreasca despre scos metrice din aplicatii PHP si despre cum ar fi complicat ca alea ruleaza pe multe pod-uri in Kubernetes si ca php-fpm iti omoara procese si ai multe procese si alte cele.

In momentul ala mi-a scaparat o idee ca se pot scoate metrici super usor, trebuie doar sa le tii undeva :))

Eu sunt asa super fan Redis ca mi se pare ca e genul ala de software scris cum trebuie (adica in C) si cu grija (adica merge repede).

M-am gandit eu vineri ca pot scrie din PHP in Redis si dupa aia sa le iau de acolo si sa le pune undeva de unde le poata lua Prometheus.

Problema asta fiind rezolvata, am ajuns la cum fac sa nu trebuiasca sa populez inainte Redis-ul cu informatii si dupa aia sa scrie aplicatia chestii pe acolo. Am zis ca’s fan Redis? E, Redix are SETNX, prin care setezi o cheie la o anumita valoare doar daca cheia aia nu exista. Si asta inseamna ca poti sa spawnezi ‘jde aplicatii care prima oara fac SETNX si dupa aia incrementeaza pe acolo contoare. Mi-am dat un self-highfive si m-am apucat de scris.

M-am apucat de scris azi, ca peste weekend am avut altele de facut, da mi-a mers acolo ganditul in background si azi stiui ce sa scriu.

Cam asta e povestea lui Enigmatique. Ca e enigmatic asa sa nu stii cate metrici o sa ai si nici Prometheus cand face scrape n-o sa stie :))

Am scris asta din doua motive mari asa:

  • Stiu ca vocile nu’s reale, dar cateodata au idei bune. Asta fu’ unu’ din cazuri.
  • Sa mai fac ceva practica cu programatul, ca nu se stie cand mai au vocile idei.

Si ii facui si logo, ca nu se stie cand e nevoie de-un logo. Sa traiasca Shopify ca are aplicatie de facut logo-uri :))

nginx conditional reverse proxy

Asta e un post din categoria despre cat de jmecher e nginx.

Am avut relativ de curand o speta in care  aveam un setup de genul:

[aplicatie interna] <---> [reverse proxy] <---> [internet clients]

si trebuia s-o securizez cumva pentru ca [aplicatia interna] e o aplicatie care accepta niste cereri HTTP (si doar HTTP) si raspunde la ele. Nu stie autentificare, nimic. E doar un fel de API endpoint super dumb. Si, evident software comercial care asa vine el si e treaba ta ca si client sa-l securizezi cumva.

[internet clients] reprezinta un software scris in-house care sta pe niste servere undeva prin internet si care are nevoie sa faca query-uri in [aplicatie interna].

Cerinta a fost relativ simpla: sa accept query-uri doar de la [internet clients] si orice alte request-uri sa le ignor.

Prima ideea a fost aia enterprise si complicata: facem SSL mutual authentication pe nginx si doar clientii care au certificat client valid in contextul asta sunt acceptati. Da era mega complicat de mentinut, ca dupa aia trebuia sa fac si management de certificate, sa le schimb periodic etc.

Varianta simpla a fost sa fac passthrough doar la cererile care aveau un header cu o anumita valoare.

location / {
 if ($http_Secret_Header = 'secretheadervalue')
  { proxy_pass http://aplicatie.interna }
 return 301 https://google.com
}

De ce e nginx super jmecher? Pentru ca toate headerele dintr-un request HTTP le pune la dispozitie in variabile prefixate cu $http_ urmat de numele header-ului. Daca headerul are cratime in el, gen My-Header, atunci ele vor fi transformate in _ (underscore) si va deveni My_Header in contextul nginx.

nginx are activat doar HTTPS cand vorbeste cu clientii si in felul asta nu se poate intercepta ce se transmite intre clienti si aplicatie.

Si variabilele pot fi folosite in reguli de genul celei de mai sus, care trimite cererea mai departe doar daca Secret-Header are valoarea secretheadervalue. Daca nu, trimite clientii la google sa caute acolo stuff pe internet ca sigur au ajuns din greseala pe serverul meu :)

Cum ziceam, [internet clients] reprezinta o aplicatie in-house si a fost mai simplu sa adauge programatorii un header in plus decat sa implementeze SSL mutual authentication.

lio fun stuff

Acu multi ani, cand voiai sa faci un target de ISCSI pe Linux, existau tgtd si tgtadm. Pen’ca tgtd rula in userspace, avea ceva penalitati de performanta, ca luai chestii de pe disk si le trimiteai peste retea. Niste oameni, adica Datera prin http://linux-iscsi.org/wiki/LIO au scris toata partea de target si initiator in kernel ca sa nu mai faci context-switching aiurea fara motiv.

Partea misto e ca pe langa ISCSI “normal” au implemenant si primitivele VAAI ale lui VMware si accelereaza diverse operatiuni pe care le face ESXi: gen zero-ing, copiere si scriere de date de pe acelasi LUN etc.

Intr-un proiect de acu aveam nevoie de shared storage pentru niste ESXi-uri si m-am apucat sa fac niste target-uri pe un CentOS7. Initial din toate discurile de aveam sa le export, am exportat unul singur mi-am facut treaba si restul sa le export cand aveam nevoie de ele.

Intr-o zi cu soare am ajuns si la exportat restul de discuri ca aveam nevoie de loc unde sa fac backup, sa mut niste masini pe niste discuri mai rapide etc.

Am adaugat si restul de discuri ca LUN-uri, le-am mapat in ESXi-uri si m-am luat cu alta treaba. A doua zi incepe lumea sa se agite ca bai nu mai merge “serverul”, unde “serverul” era un VM pe care lucrau oamenii. Pana a ajuns la mine asta, pana am terminat ce aveam de facut, a inceput sa mearga “serverul”. Am zis ca cine stie, o fi sughitat reteaua sau ceva (ca lumea era pe Wi-Fi si na… nu e obligatoriu sa mearga mereu ca te mai pui cu laptop-ul aiurea si poate nu ai cel mai bun semnal) si d’aia n-a mers, ca nici nu a stiu lumea sa-mi spuna exact ce inseamna “nu merge”.

A doua zi dupa incident, eram eu pe langa rack-uri si trageam de niste cabluri pe acolo, cand aud un bipait din ala de cand buteaza un server. M-am apucat sa ascult sa vad de unde e, da pana am gasit un monitor, pana l-am montat, pana am luat-o din server in server, totul era iar OK. Dupa aia am luat-o cu verificat de uptime-uri, pana dau de asta cu storage care avea uptime de cateva minute.

Evident, dictai WTF-ul pe fata mea, ca n-atinsesem nimic care sa-l afecteze. Noroc ca mai eram cu cineva acolo pe post de martor, ca zicea lumea ca-i sabotez. E, cat incercam io sa ma uit in loguri sa vad ce-ar fi putut sa aiba (bine, sperand sa gasesc loguri), vad cum incepe un kdump sa ruleze si buf, reboot iar.

Cat am apucat io sa vad ce scria pe ecran, baga ceva cu “BIOS corrupted by…”. Zic sa vezi acu distractie, ca daca e ceva de BIOS si nu exista update la producator, o sa se lase cu sugeri maxime, ca aia n-o sa fixeze peste noapte si o sa dureze pana se prind ce ma-sa are.

Cat ma gandeam eu la posibilitati si ce-ar putea sa aiba, s-a rebutat, a pornit fain frumos, a mai mers vreo 10-15 minute si iar kdump si biiip restart.

Eram asa un pic cu morcovul in cur ca 1) lumea chiar avea nevoie de storage pentru VM-uri 2) eu propusesem solutia. Mai mult 2) ma ardea maxim. Ca ma gandeam c-am pizdit-o grav. Desi era prima oara cand se intampla asta, am auzit de atatea ori scuza asta la diversi cu “pana acu nu mi s-a intamplat” ca ma gandeam ca sigur o sa ma creada din parti clientul daca zic si io asta. Ca eu sigur nu l-as fi crezut pe unul cand zice asta.

Si m-am apucat sa ma gandesc ca ma-sa s-a schimbat intre timp, ce-am facut, unde, de ce. Si nu imi venea nimic in cap sa fi facut acolo, care sa prezinte un risc. Pana cand dupa vreo ora asa, si vreo 2 reboot-uri, m-a palit ca poate e de la ISCSI ca adaugasem alea 2 LUN-uri in portal.

Le-am demonat de pe ESXi-uri, le-am sters din portal si am asteptat sa vad daca mai crapa.

Si n-a mai crapat.

Dupa ce mi-a trecut sperietura cu asta, am inceput sa ma gandesc ca “ba bine, nu mai crapa, da acu ce cacat fac cu restul de discuri, ca nu pot sa nu le mai prezint la ESXi-uri, ca am nevoie de ele”. Cat timp ma gandeam eu la asta, mi-am adus aminte de kdump. Si m-am apucat sa ma uit prin ele, ca se salvasera toate de cand a inceput sa moara kernelul.

Si mi-a trecut panica, ca absolut de fiecare data crapa in acelasi loc:

[ 5241.534120] BUG: unable to handle kernel NULL pointer dereference at 000000000000001c
[ 5241.534194] IP: [<ffffffff816abb5c>] _raw_spin_lock+0xc/0x30
[ 5241.534245] PGD 0 
[ 5241.534264] Oops: 0002 [#1] SMP 
[ 5241.536014] Call Trace:
[ 5241.536048] [<ffffffffc05d1c90>] ? target_complete_ok_work+0x180/0x330 [target_core_mod]
[ 5241.536109] [<ffffffff810a881a>] process_one_work+0x17a/0x440
[ 5241.536153] [<ffffffff810a94e6>] worker_thread+0x126/0x3c0
[ 5241.536196] [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
[ 5241.536244] [<ffffffff810b098f>] kthread+0xcf/0xe0
[ 5241.536281] [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
[ 5241.536327] [<ffffffff816b4f58>] ret_from_fork+0x58/0x90
[ 5241.536367] [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
[ 5241.536410] Code: 5d c3 0f 1f 44 00 00 85 d2 74 e4 0f 1f 40 00 eb ed 66 0f 1f 44 00 00 b8 01 00 00 00 5d c3 90 0f 1f 44 00 00 31 c0 ba 01 00 00 00 <f0> 0f b1 17 85 c0 75 01 c3 55 89 c6 48 89 e5 e8 a4 2a ff ff 5d 
[ 5241.536649] RIP [<ffffffff816abb5c>] _raw_spin_lock+0xc/0x30
[ 5241.536694] RSP <ffff88085de0fdf8>
[ 5241.536720] CR2: 000000000000001c

Bine, mi-a trecut panica ca m-am gandit eu ca ba, sa vezi ca se confuzeaza in vreo chestie de concurrency ca mai multe host-uri vor chestii relativ similare de pe mai multe discuri in acelasi timp si poate se dezaloca ceva aiurea si d’aia ajunge ala in NULL pointer dereference. Sau poate cand aloca nu si incrementeaza numarul de alocari si prima dezalocare merge da restul nu mai au cum… Sau ceva de SerDes aiurea la scrieri/citiri.

Da’ fiind in _raw_spin_lock cand crapa… slabe sanse sa pot debuga ceva, ca asta e treaba de lucruri low level in kernel.

Long-story short: mai multe LUN-uri intr-un portal exportate la mai multe host-uri != love.

Acum stiam de ce crapa, da nu-mi rezolva problema, si anume sa pot folosi toate discurile din sistem.

Si mi-am adus aminte ca atunci cand am mai avut probleme din astea cand nu mergeau mai multe lucruri in acelasi timp in kernel am folosit VM-uri se separ pe caprarii componentele.

Asa am ajuns ca pentru fiecare disc pe care trebuie sa-l export sa fac cate o masina cu KVM la care sa-i atasez discul din host, sa fac cate o configuratie simpla de ISCSI target si s-o prezint mai departe la ESXi-uri. E o solutie scarpinata pe dupa ureche, da’ merge si pentru ca virtualizare si discuri din host in VM direct, nu se observa nici un overhead.

Nu e cea mai eleganta solutie, dar merge fara prea mult efort de administrare.

ipv6 & ipsec & bugs

Mai anul trecut la inceput de vara ma jucam io in niste masini virtuale cu Layer2 peste Layer3 in Linux. Anul asta am gasit un client unde sa bag jucaria in productie sa vad ca toate treburile merg cum trebuie si pe bune :)

Eh, pentru ca atunci cand ai optiuni multe iti vin idei, am zis ce-ar fi daca intre 2 gateway-uri de VPN as face io conexiunea pe IPV6 in loc de IPv4, ca e bine sa fim pregatiti de viitor :))

Am pus io doua CentOS 7, configurat interfete & shit, am pus libreswan, am facut un tunel IPSec si am dat ping6 intre cele doua masini si a mers jucaria (tcpdump zicea ca vede ESP pe fir).

Ca oricem om prevazator, zic sa dau reboot ca poate am uitat sa configurez ceva sa porneasc la boot si daca ramai fara curent sau s-o panica kernelul de singuratate, sa mearga treaba cand dai restart de la buton.

Si dau io restart si evident ca pula tunel. ipsec status zicea ca e in CONNECTING, da nici in loguri si nici pe fir nu vedeam vreun pachet plecat la alalalt gateway. Ce-are, ce-are. Dat restart la libreswan, o lua. Am zis ca poate e vreo problema cu libreswan, ca mai dadusem de una draguta un pic inainte.

Aia draguta era misto, ca fix imediat dupa boot nu voia sa ridice tunelul de nici un fel. ipsec auto –up $nume_conexiune zicea ca nici una din cheile RSA nu e buna de folosit pentru autentificare, insa fara a modifica nimic, dupa un libreswan restart brusc deveneau bune cheile.

De draci ajunsesem la o varianta taraneasca, dupa pornirea sistemului sa-si dau un start/stop manual s-o ia.

Hai ca zic merge tunelul, sa fac niste teste de trafic cu ping6 sa vad daca MTU-ul e cum trebuie, dau io ping6 -s 1500 si timeout. Pe la vreo 1300 bytes si ceva payload mergea. Pun de mana MTU-ul la 9000 (ca interfete gigabit) si dau iar ping6, si iar timeout. Mai dau si un restart lu’ libreswan (ca vorba aia: when in doubt, restart) ca poate fiind pornit se uita o data la MTU si dupa aia o tine cumva cont de el. tcpdump zicea ca pachetele pleaca da nu ajung.

Uite asa m-am trezit io in zona crepusculara, unde lucrurile in teorie trebuiau sa mearga iar in practica erau diferite de teorie. Si e frustrant ca zici ca, mortii ma-sii, e un VPN, mai mult de cateva ore n-are ce sa ia, ca doar ma dau cu IPsec pe Linux de cand eram mic si stiam ce fac.

Dupa o zi de injuraturi, am oprit IPSec, si zic hai ca in clar tre sa mearga cacatul si o iau dupa aia pe dos sa vad unde se strica. Intre astea doua masini aveam un switch ca sa simulez realitatea. Si zic sa pun un cablu direct intre ele sa elimin orice element in plus care ar putea sa induca erori.

Evident, cu cablu direct mergea treaba de n’avea aer. Acuma switch-ul avea porturi gigabit si cablurile erau bagate in el in porturile alea. Si totusi ce n’avea switch-ul pe porturile gigabit? Jumbo frames in pizda ma-sii. Jumbo frames n-avea. Ca HP in vasta sa inteligenta s-a gandit ca probabil nu sunt bune si n-a implementat suport pentru ele in switch. Si uite asa ai conexiune la gigabit da cu frame-uri de maxim 1504 bytes, sa incapa si un VLAN tag acolo da nimic in plus.

Dupa dracii cu HP, m-am intors la problema initiala, de ce ma-sa dupa reboot n-o ia tunelul. S-a facut tarziu si m-am dus sa dorm.

Evident ca n-am dormit ca ma rodea problema, mi-am facut repede un laborator cu doua CentOS 7 si zic sa incerc strongswan in loc de libreswan, ca poate o avea ala suport mai bun pentru ce fac. Suport in a vorbi cu framework-ul de XFRM din kernel unde se intampla magia.

Fac repede o configuratie si dau reboot la un nod, si dupa reboot pula tunel. Dupa niste tcpdump ma loveste problema: Cand un neighbor IPv6 vrea sa afle ce adresa MAC are alt neighbor, trimite pe multicast FF02::1 un mesaj de Neighbor Solicitation (echivalent de mesajul trimis pe broadcast in IPV4 pentru a afla MAC-ul unui computer din reteaua locala) si primeste unicast un raspuns.

Ce se intampla in kernel in combinatie cu IPSec-ul: pachetele de solicitation plecau cum trebuie si ajungeau la alalalt nod, ala raspundea unicast si nodul care a trimis solicitarea le ignora pentru ca… tananana… se astepta sa fie criptate conform configuratiei (SA-urile erau facute intre 2 /128).

Acu la 2 noaptea stiam care e problema, sa o si rezolv:

conn ipv6nd
   auto=route
   keyexchange=ikev2
   authby=never
   type=passthrough
   leftsubnet=2001:abc:def:ffff::2/128[ipv6-icmp/136]

Unde leftsubnet reprezinta IP-ul aluilalt gateway, iar pe ala se face pe dos configuratia. Et voila, merg chestiile dupa configuratia asta.

Ce inseamna ce-am facut mai sus? Inseamna ca sistemul va accepta pachete ICMPv6 Neighbor Advertisement necriptate. E important ca regula asta sa fie scrisa prima in config ca sa aiba precedenta fata de urmatoarele. E ca la firewall, de sus in jos :)

Asa, acu c-am rezolvat-o, am trecut la pasul urmator. Tipul conexiunii era de tip transport, ca aveam treaba sa protejeze doar traficul intre cele 2 gateway-uri.

Peste am facut un tunel L2TPv3 si cateva sesiuni sa car niste VLAN-uri dintr-o parte in alta. Pe fiecare cap aveam o interfata fizica cu tag-uri de VLAN, una de pseudowire, ambele bagate intr-un bridge.

Pe o interfata de bridge am pus o adresa IPv4, la fel si pe alalalt gateway si minune… mergea ping-ul intre ele. Scopul declarat fiind sa le folosesc pe post de adrese de management pe un VLAN de management.

Cu experimentul pe IPv4 reusit, am pus un set de adrese IPv6 pe interfetele de bridge asteptand acelasi rezultat. Si-am asteptat, si-am asteptat… cum asteapta un caine parasit stapanii care nu se mai intorc.

Pentru ca IPv6 e special, cand ai o adresa pusa pe interfata de bridge, neighbor solicitation nu se duce doar pe interfetele de compun bridge-ul, ci pe toate interfetele din sistem, mai putin pe alea de pseudowire.

Aci ma panicasem un pic, ca sa nu pot sa fac management pe IPv6 nu era un capat de lume, da incepusem sa ma gandesc ca daca se intampla la fel si pe trafic intre 2 host-uri din acelasi VLAN care trec prin jucaria mea?

Well, aci am avut noroc si asta nu se intampla. De aflat am aflat testand si injurand iar HP-ul ca are ceva cu pachetele de IPv6 multicast si nu merge Neighbor Discovery. O sa investighez daca intr-o versiune mai noua de firmware au facut lucrurile sa mearga.

De ramas am ramas la strongswan din mai multe motive:

  • pare mai robust fata de libreswan
  • suporta DH Group 19/20/21 (curbe eliptice, chei mai mici, securitate mai mare)
  • suporta chei de tip ECDSA (cu ocazia asta mi-am facut si niste certificate digitale pe 521biti de tip Elliptic Curve)
  • nu are dilemele lui libreswan cu cheile (ba sunt bune, ba nu sunt bune)
  • merge OK partea de fragmentare a pachetelor care depasesc MTU la nivel de IKE (e misto sa dai ping cu -s 65000 si sa mearga fara sa faci nimic)
  • are suport de TFC (traffic flow confidentiality) pe IKEv2 in mod tunel. Asta inseamna ca face padding pana la MTU-ul interfetei si indiferent de cat trafic ai de fapt, unu care sta cu urechea pe fir va vedea mereu pachete de 9000 bytes (in cazul gigabit ethernet), fara sa stie exact cat sunt date utile si cat e gunoi.

Cu procesoare care au AES-NI (Intel Ivy Bridge sau mai noi) exista si accelerare hardware pentru criptare, via aesni_intel, mai ales daca AES e folosit in GCM. La fel, functiile de hash pentru integritatea datelor pot fi efectuate direct pe procesor prin sha512-ssse3 daca se foloseste SHA512 la IPSec.

Long story short, merge. Bine, merge da violat un pic tot setup-ul ca am dat de un bug in kernel care e nefixat in toate versiunile cu care am testat, adica de la 3.10 la 4.5 sau 4.10 cat era ultimul din CentOS 7 plus cand am testat.

BUG-ul e super misto: dupa cam o saptamana, moare treaba si fara reboot nu-si revine. Si asta se intampla pe ambele gateway-uri.

Dupa miliarde de draci si debug in fata serverului cu monitor si tastatura ca in vremurile bune, am descoperit problema, si anume un leak in kernel, mai mult de file descriptors din ce am bunghit pana acum.

Ce se intampla, ca e atunci cand se schimba cheile, nu se face free la esp6 si xfrm6 daca pe aceasi masina e si un tunel L2TP pentru setup-ul de pseudowires. Si creste utilizarea modulelor pana se strica jucaria.

[root@vpn-gw-1-1-c7-v ~]# lsmod | grep esp6
esp6 17180 1566 
[root@vpn-gw-1-1-c7-v ~]# lsmod | grep xfrm6
xfrm6_mode_transport 12631 3132

Si cand ajungi la cateva sute sau chiar mii, pocneste si nu mai merge. Si asta doar in combinatie cu modulul de L2TP pentru IPv6.

Pentru a rezolva asta, varianta cea mai buna a fost sa fac o masina virtuala in care sa termin partea de L2TP. Adica pe masina fizica am partea de IPSec intre capete, dupa care pe masina virtuala am facut multe interfete: una de inbound pe unde vin pachetele de L2TP si multe pe care sa scot pachetele in cate in un bridge, VLAN tagged sa le dau mai departe.

Postul asta trebuia sa-l public anul trecut cam acum (28 Septembrie 2016), da am uitat de el, da nu conteaza, ca BUG-ul nu e fixat nici acu si jucaria merge de atunci, line rate, fara nici o problema. Ar fi frumos sa fie si BUG-ul ala fixat pentru simplificarea setup-ului.

Cum setup super perfect nu exista, acum e un pic urata adaugarea de noi VLAN-uri pe acelasi pseudowire, in sensul ca trebuie sa le adaug de mana si sa editez si fisierele de configuratie astfel incat sa fie ce trebuie la reboot. Asta e din cauza ca pe CentOS nu exista script de network pentru a seta interfete de tip l2tp_eth. Insa e OK, ca nu schimb zilnic setari.

ubuntu 16.04 pxe install

De anul trecut am trecut incet, incet spre DevOps. Mai bag si pe security, da mai rar in ultima vreme.

Doar Ops n-am mai facut de ceva vreme si evident, ca m-am mai ramolit un pic pe partea asta. Iar cu Dev-ul din DevOps  o lalai in Python, ca e bun pentru a programa chestii de sistem.

Pentru un client nou, am avut de facut un server de deployment pentru niste servere fizice astfel incat sa bagi serverul poaspat scos din cutie in priza, sa-l conectezi la retea si 15min mai tarziu sa-l ai instalat. Bine, depinde de viteza mirror-ului asta, ca prin unele tari merge intrnetul de zici ca’l aduc cu galeata.

Ca si distro am folosit Ubuntu 16.04 LTS pentru ca $reasons.

Partea usoara e sa instalezi un server de TFTP si un server de DHCP care sa aloce IP-uri si sa spuna la clienti cum se cheama fisierul pentru BOOTP.

Ca si server de deployment am folosit tot un Ubuntu 16.04, sa fie instalarea intre prieteni sa mearga bine si fara probleme :))

Si pentru ca multe servere, evident ceva care sa faca orchestrare si management. Si ca ziceam mai sus ca o lalai cu Python, SaltStack a fost raspunsul.

Asa ca, cum se face sa deployezi multe servere fizice in vremea lui AWS, GCP si Azure:

  1. Se instaleaza atftpd, se modifica  /etc/default/atftpd si se schimba USE_INETD din true in false. Dupa care systemctl enable atftpd si systemctl start atftpd.
  2. Se downloadeaza un ISO de Ubuntu Server 16.04 si se monteaza cu loop pe sistem.
  3. Se copiaza de unde s-a montat ISO continutul directorului netboot in /srv/tftp.
  4. Dupa nevoie se editeaza /srv/tftp/boot-screens/menu.cfg astfel incat sa bata cu realitatea la fata locului. Cateva note la exemplul meu:
    1. installerul e retardat si daca serverul de DNS raspunde cu AAAA RRs, o sa vrea sa se conecteze pe IPv6 la mirror, chiar daca nu are ruta default pe IPv6.
    2. A.B.C.D se inlocuieste cu adresa IP a serverului de TFTP
    3. eno3 e cum stiu eu ca se cheama interfata de retea pe care o foloseste masina ce va fi instalata pentru DHCP, pentru ca in cazul meu aveam mai multe interfete si se blocheaza installer-ul si te pune sa alegi una (chiar si cu optiunea auto tot la fel face).
  5. Se creeza /srv/tftp/preseed/ubuntu-16.04-preseed.cfg unde se va scrie configuratia pentru installer. La fel, cateva note la exemplul meu:
    1. Installer-ul va crea un setup de tip RAID10 din primele patru discuri de pe sistem. Recipe-ul de RAID l-am bunghit cu #mumu help, ca nu prea e documentat cum se face. E un pic de magie in toata treaba aia.
    2. Peste va configura LVM si / va fi un LV de 30GB pe VG-ul nou creat.
    3. In cazul in care masina va avea mai multe interfete de retea, trebuie specificat ce intefata sa foloseasca in mod automat. Altfel va sta ca boul asteptand sa selectezi pe care sa o folosesti.
    4. $magic_postinstall_setup_script poate fi orice script (bash, python, perl etc.) care face chestii pe sistem inainte de reboot dupa instalare. Scriptul asta de obicei se pune pe un server web, se downloadeaza si se executa. O sa revin mai tarziu cu ce si cum.
  6. Se instaleaza isc-dhcp-server si se modifica /etc/dhcp/dhcpd.conf sa dea adrese dintr-un pool la clienti si se adauga urmatoarea optiune in definitia de subnet:
  7. filename "pxelinux.0";

    systemctl enable isc-dhcp-server si systemctl start isc-dhcp-server.

  8. Se buteaza o masina fizica si se asteapta pana termina de instalat. Daca da oroare sa ceva, trebuie fixata in fisierul de preseed, reboot si de la cap cu instalarea pana merge. Nu exista checker pentru fisierul de preseed. Pe mine m-a enervat maxim treaba asta ca instalarea se facea pe niste Dell R430 si pana buteaza alea mori incet.

Ziceam mai sus ca inainte de reboot, pot da comenzi in sistemul nou instalat sa-l configurez cumva inainte sa porneasca prima oara.

d-i preseed/late_command string \
 in-target wget -P /tmp/ -t 0 -c http://A.B.C.D/myscript.sh; \
 in-target chmod +x /tmp/myscript.sh; \
 in-target /tmp/myscript.sh; \
 in-target wget -P /tmp/ https://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest/SALTSTACK-GPG-KEY.pub; \
 in-target apt-key add /tmp/SALTSTACK-GPG-KEY.pub; \
 /bin/echo "dev.raid.speed_limit_max = 1000000" >> /target/etc/sysctl.conf; \
 /bin/echo "deb http://repo.saltstack.com/apt/ubuntu/16.04/amd64/latest xenial main" > /target/etc/apt/sources.list.d/saltstack.list; \
 in-target apt-get update; \
 in-target apt-get install -y salt-minion

Se pot da comenzi succesive in late_command. Ce trebuie stiut:

  1. Cuvantul in-target ii zice installer-ului sa faca chroot() in noul sistem si sa execute comanda de acolo.
  2. Comenzile date fara in-target se ruleaza de pe mediul de instalare (din installer cum s-ar zice).
  3. Se foloseste combinatia normala + in-target ca unele comenzi nu merg in chroot, ca de exemplu echo $stuff merge doar din installer, in chroot nu merge. Poate imi scapa mi ceva, dar sa stau sa debughez asta dura prea mult.

Ziceam ca pentru orchestrare si configurare am mers pe SaltStack. Eu pentru ca are minioni, colegul de proiect ca i s-a luat de Puppet. Bine, nici eu nu m-am omorat dupa Puppet ca e scris in Ruby.

Cine a facut SaltStack asta a fost inteligent si minionii daca n-au nici o configuratie, o sa incerce sa se lege la salt.domain.name. Si asta inseamna ca tot ce trebuie sa am este un salt-master instalat si configurat acolo un pic, configurat DNS-ul atfel incat salt.domain.com sa bata la un serverul pe care ruleaza salt-master si, dupa ce fiecare masina fizica se rebuteaza, minionul se va conecta automat la salt-master. Magie adevarata.

salt-key –accept-all este raspunsul la intrebarea cum confirm ca minionii inregistrati sunt ai mei :)

turop

Pentru un proiect de-al meu, in scop didactic, am nevoie sa pot emite certificate digitale cat mai usor cu putinta. Si cum tot am inceput sa mai apas butoane si in limbaje de programare, am zis ca ce bine, pot sa scriu ceva simplu pe web.

Asa ca azi am creat turop, o aplicatie web in care cine are nevoie face paste la CSR si primeste un certificat digital inapoi. E mega quick & dirty, in special dirty. Da merge si isi face treaba.