Un daemon VPN are nevoie de operații de rețea privilegiate, deși aplicațiile obișnuite deschid socketuri de ieșire fără niciun privilegiu. În acest gol încep majoritatea erorilor de capabilități: cineva vede o eroare de permisiune, acordă întregul set, iar serviciul funcționează din motive pe care nimeni nu le mai poate explica. Turul de mai jos pornește de la operația care a eșuat, o asociază unei singure autorități și apoi verifică contextul în care procesul rulează de fapt. Rularea ca root fără restricții este un răspuns valid pentru unele implementări, dar ar trebui să fie o decizie, nu o valoare implicită.

Pornește de la operația care a eșuat

Citește eroarea înainte de a citi un tutorial. „Operațiune nepermisă” la o modificare de interfață, refuzul de a deschide un nod de dispozitiv și o eroare de bind pe un port jos sunt trei probleme diferite cu trei acordări diferite. Dacă procesul pornește și eșuează doar la prima schimbare de rută, asta arată și că crearea interfeței a reușit deja, ceea ce restrânge mult răspunsul.

Reprodu eroarea cu serviciul oprit, apoi pornește-l în prim-plan sub același utilizator dacă implementarea permite. O eroare pe care o vezi e mai bună decât o linie de jurnal pe care trebuie să o ghicești, și face evidentă diferența dintre o problemă de capabilități și un refuz din SELinux sau AppArmor.

Asociază fiecare operație unei singure autorități

Tabelul este o hartă de pornire, nu un substitut pentru documentația implementării:

OperationUsual authorityWatch for
Create or configure tun/tapCAP_NET_ADMIN in the relevant namespaceCreating the device and opening it are separate steps
Add routes, rules, firewall entriesCAP_NET_ADMINSame capability, different namespace than you think
Open /dev/net/tunDevice permissions, not a capabilityGroup membership or a udev rule may be enough
Raw socketsCAP_NET_RAWNeeded by some user-space tunnel implementations
Bind a port below 1024CAP_NET_BIND_SERVICEIrrelevant for most modern tunnel ports

Cele două rânduri din acel tabel sunt cele pe care oamenii le confundă. Deschiderea /dev/net/tun este o problemă de permisiuni de fișier; cererea către kernel de a configura ce ai deschis este o problemă de capabilități. Acordarea CAP_NET_ADMIN nu repară un nod de dispozitiv pe care utilizatorul serviciului nu îl poate citi, iar repararea nodului nu îți dă autoritate pe rute. Verifică ambele înainte de a schimba vreuna.

WireGuard din kernel și programele de tunel din spațiul utilizator nici nu au cerințe identice. Calea modulului de kernel configurează o interfață existentă prin netlink, în timp ce o implementare din spațiul utilizator poate avea nevoie și de dispozitiv și, pentru unele transporturi, de socketuri brute.

Citește contextul: serviciu, container sau shell

O capabilitate în spațiul de nume de rețea al gazdei poate afecta mult mai mult decât aceeași operație într-o stivă izolată intenționat. Un mediu de execuție pentru containere pornește de obicei cu un set de limite redus; adăugarea NET_ADMIN la un container care partajează rețeaua gazdei este o acordare mult mai mare decât adăugarea lui la unul cu propriul spațiu de nume de rețea și fără montări ale gazdei.

Pentru unitățile systemd citește ce se aplică de fapt, nu ce pare să spună fișierul unității: systemctl show -p CapabilityBoundingSet -p AmbientCapabilities raportează valorile efective, care pot fi stabilite de un drop-in uitat. Cere valoarea efectivă, niciodată pe cea intenționată. Capabilitățile ambient contează pentru că un serviciu care nu este root pierde capabilități prin exec fără ele.

Ia ca bază configurarea suportată a pachetului sau a imaginii. Nu adăuga permisiuni pentru socketuri brute sau mod privilegiat doar pentru că alt tutorial le-a listat pentru alt instrument; raționamentul acela nu transferă nimic și te costă izolarea pentru care ai plătit. Când ai îndoieli, nu acorda nimic și citește notele implementării pentru operația exactă de care ai nevoie.

Urmărește ce se întâmplă după ce privilegiile scad

Multe daemon-e pornesc privilegiate, configurează interfața, apoi trec la un utilizator neprivilegiat și păstrează tunelul. Din acel moment procesul nu mai poate adăuga o rută, rescrie o regulă de firewall sau deschide un dispozitiv privilegiat nou, ceea ce este în regulă până când o reconectare are nevoie exact de asta. Citirile de fișiere și execuția de hook-uri ulterioare pot eșua din același motiv.

Testează întregul ciclu de viață, nu prima secundă: pornirea, o reînnoire sau reconectare și curățarea la oprire. O primă creare reușită a interfeței nu dovedește că fiecare operație privilegiată ulterioară va funcționa în continuare, iar eșecul apare de obicei ore mai târziu în producție.

Implementările care țin tunelul deschis peste o schimbare de utilizator combină de obicei asta cu opțiuni de păstrare a tunelului și a cheilor. Pe partea systemd, întrebarea echivalentă este dacă setul de capabilități al unității supraviețuiește schimbării de utilizator pe care ai configurat-o.

Notează acordarea și motivul ei

Scrie acordarea exactă, operația pe care o permite și eroarea pe care a reparat-o. O singură linie în notele de implementare — „CAP_NET_ADMIN în spațiul de nume de rețea al unității, necesar pentru schimbările de rută după reconectare” — este suficientă ca să împiedice următoarea persoană să lărgească din nou acordarea.

Apoi recitește setul efectiv după fiecare actualizare. Furnizorii adaugă funcții, imaginile schimbă valorile implicite, iar o capabilitate inutilă anul trecut poate deveni portantă fără ca nimeni să observe.

Articole similare