Un timp lung de funcționare dovedește doar că pornirea a reușit cu privilegiile pe care le avea daemonul în acel moment. Defectările care contează aici vin mai târziu: un client nou se conectează, o listă de revocare este înlocuită, un script auxiliar trebuie să scrie un fișier. Fiecare este o deschidere nouă făcută de contul fără privilegii, cu propria întrebare despre permisiuni și propriul mesaj de eroare. Trei decizii separă o configurație care continuă să funcționeze de una care eșuează la următorul eveniment.

Separați ce a fost încărcat devreme de ce se deschide mai târziu

Un descriptor este un mâner pe o descriere de fișier deschisă, iar modul de acces a fost fixat când a fost creată acea descriere. Schimbarea ulterioară a utilizatorului procesului nu închide mânerul, de aceea un fișier de cheie citit ca root funcționează și după reducere. Nici modul nu se schimbă: un mâner deschis pentru citire nu devine scriibil, iar un mâner scriibil nu este retras doar pentru că contul și-a pierdut drepturile pe cale. Aceste două fapte explică cea mai mare parte a comportamentului surprinzător din aceste rapoarte.

Cealaltă jumătate este memoria. Daemonul poate analiza un certificat, păstra materialul analizat și închide fișierul; ceea ce rămâne în uz sunt date, nu un fișier deschis. Prin urmare traficul continuu nu dovedește nici că un descriptor este deschis, nici că numele căii este accesibil. Dovedește doar că materialul necesar sesiunii curente a fost obținut mai devreme.

O deschidere ulterioară este altă tranzacție. Rulează sub acreditările curente, contextul de securitate curent și vederea de montare curentă, așa că o cale lizibilă la pornire poate fi refuzată la conexiunea următoare. Rotația adaugă o capcană: scrierea unui fișier nou peste același nume de cale lasă un descriptor existent legat de obiectul vechi, așa că o reîncărcare poate părea reușită în timp ce daemonul folosește încă conținutul anterior. Comparați inode-ul ținut de proces cu cel de pe disc înainte de a crede într-o rotație.

Numiți cele trei citiri de execuție și când are loc fiecare

Trei resurse sunt deschise de obicei mult după inițializare și eșuează în momente diferite. Un fișier de configurare specific unui client este citit când acel client se conectează, deci poate ceda pentru un utilizator în timp ce ceilalți continuă. Datele de revocare sunt consultate în timpul autentificării partenerului și din nou când fișierul este înlocuit. Un director temporar este atins doar când un script sau un modul scrie ceva.

Niciuna dintre cele trei nu aparține căii de pornire, de aceea un server sănătos săptămâni întregi poate eșua la conexiunea următoare. Categoria numește și proprietarul corecției: primele două sunt permisiuni de citire pe configurație sub contul daemonului, iar a treia este o locație scriibilă cu un scop îngust.

Path reopened laterWhat triggers the openFirst sign when it fails
Client configuration fileA connection for that client identityOne client rejected while others connect
Revocation dataPeer authentication, including after replacementRevoked and valid peers both refused
Script or plugin temporary directoryA helper needs to create a fileThe helper exits with a path error

persist-key răspunde la o întrebare mai îngustă decât presupun majoritatea. Păstrează fișierul de cheie deschis pe durata resetărilor documentate SIGUSR1 și ping-restart, și nu face nimic pentru fișierele CCD, datele de revocare, executabilele auxiliare sau o repornire completă a procesului. Acelea urmează în continuare propriile căi de deschidere, sub orice cont rulează atunci.

Confirmați contul și vederea pe care o are de fapt

Întrebați daemonul care rulează ce cont folosește, în loc să vă bazați pe fișierul unit, apoi comparați răspunsul cu ce stabilește unitul. O nepotrivire este primul lucru de rezolvat, pentru că fiecare verificare ulterioară a permisiunilor rulează ca cel care este procesul în realitate. Apoi parcurgeți calea componentă cu componentă; traversarea este evaluată la fiecare nivel, așa că un fișier lizibil într-un director netraversabil rămâne ilizibil. Modul final al fișierului este ultima întrebare, nu prima.

Spațiile de nume și cutiile de nisip ale serviciului adaugă limite pe care proprietatea și biții de mod nu le descriu. O cale vizibilă în shell-ul dumneavoastră poate lipsi sau poate fi doar pentru citire într-un chroot, într-un spațiu de nume de montare sau într-un unit care ascunde directoarele personale. Modulele de securitate adaugă încă un strat, așa că un fișier care pare lizibil poate fi totuși refuzat la deschidere.

ps -o user:12,pid,args -C openvpn
systemctl show -p User -p Group -p ProtectHome -p RootDirectory [email protected]
sudo -u openvpn namei -l /etc/openvpn/ccd/alice

O citire reușită în shell-ul administratorului nu testează niciuna dintre aceste condiții combinate. Rulați verificarea ca contul daemonului, cu același spațiu de nume și aceeași cutie de nisip, sau acceptați că rezultatul descrie shell-ul dumneavoastră, nu serverul. A treia comandă este versiunea ieftină a acelui test: tipărește modul fiecărei componente și eșuează la prima pe care contul daemonului nu o poate traversa.

Dați scrierii de execuție un director propriu

Citirea este doar jumătate din inventar. Un script auxiliar poate avea nevoie să creeze un fișier de stare, un modul poate avea nevoie să scrie stare lângă configurația sa, iar acele scrieri nu sunt acoperite de a face arborele de configurație scriibil. Dați directorului concret permisiunea de scriere de care are nevoie funcția sa, cu un proprietar și un mod pe care le puteți explica. Preferați accesul doar pentru citire pentru tot ce este doar citit.

Țineți permisiunile cheii private separate de fișierele de politică. O cheie care trebuie recitită după o resetare are o cerință diferită de un fișier de client citit la fiecare conexiune, iar un singur mod permisiv pentru ambele acordă mai mult acces decât cere problema. Un cont de daemon dedicat cu proprietate îngustă este mai ușor de auditat decât un grup larg. Când cheia trebuie să supraviețuiască resetărilor, persist-key elimină recitirea în loc să lărgească directorul.

Decideți pornind de la evenimentul pe care îl puteți reproduce

Un tunel activ dovedește o singură cale prin cod. Evenimentul care are nevoie de fișier este singurul test care acoperă deschiderea care vă interesează, fie că este o conexiune nouă de client, un fișier de revocare înlocuit, o resetare blândă permisă sau o repornire planificată. Alegeți evenimentul, rulați-l și păstrați prima eroare, nu pe ultima.

Pentru o resetare blândă, un semnal și jurnalul unitului arată dacă cheia a fost recitită. Trimiteți semnalul, apoi citiți ultimele linii pe care le-a scris unitul:

systemctl kill -s SIGUSR1 [email protected]
journalctl -u [email protected] -n 40 --no-pager

Nu concluzionați că un daemon compromis nu mai poate modifica fișiere doar pentru că privilegiile au fost reduse. Ce mai poate depinde de acreditările rămase, de capacitățile sale, de directoarele în care poate scrie și de orice descriptor scriibil pe care îl mai deține. Reducerea privilegiilor îngustează autoritatea, iar inventarul deschiderilor de execuție arată cât de mult. Scrieți această limită lângă configurație, ca următoarea persoană să nu o descopere din nou.

Articole similare