Ekzekutoni një veprim pas lidhjes VPN si përdoruesi, jo si daemon
Një variabël mjedisi që thotë USER=alice nuk ndryshon se në cilën llogari ekzekutohet një hook. Ndani ngjarjen, shkaktuesin dhe veprimin, pastaj provoni UID.
Hook-et e lidhjes në një daemon VPN ekzekutohen si daemoni, dhe zakonisht kjo do të thotë se ekzekutohen si root. Në momentin kur një prej këtyre hook-eve shkruan në drejtorinë shtëpiake të dikujt ose rinis një asistent desktopi, i keni dhënë një ngjarjeje rrjeti aftësinë të veprojë si çdo përdorues lokal. Shkurtesa e zakonshme, leximi i një emri përdoruesi nga një variabël mjedisi dhe kalimi i tij, nuk e rregullon këtë. Ajo thjesht rietiketon veprimin pa ndryshuar se cila llogari e kryen atë. Ajo që funksionon është një dorëzim në tre pjesë, ku hapi i privilegjuar thotë çfarë ndodhi dhe një njësi e veçantë kryen veprimin nën identitetin e duhur.
Një emër përdoruesi në mjedis nuk është ndërprerës identiteti
Unix vendos se çfarë mund të prekë një proces sipas ID-së së tij efektive të përdoruesit, jo sipas vargjeve në mjedisin e tij. Vendosja e USER=alice ose eksportimi i LOGNAME ndryshon atë që shtyp software i pakujdesshëm në daljen e tij; nuk ndryshon asgjë në kontrollet e pronësisë së skedarëve. Një hook që ekzekutohet si root me atë variabël të vendosur hap gjithsesi skedarët e Alice si root.
Edhe emrat nuk janë i njëjti emër. Hyrja për akses në distancë, llogaria lokale Unix dhe emri i përbashkët i certifikatës janë tre identifikues që shpesh përputhen dhe ndonjëherë jo. Një përdorues që vërtetohet si a.smith mund të mos ketë fare llogari lokale, ose mund të mapohet në asmith përmes një shërbimi drejtorie. Çdo dizajn që supozon se një varg i shërben të tre roleve do të thyhet te kontraktori i parë.
Pra pyetja e parë nuk është «cili përdorues është i lidhur» por «cilës llogari lokale i lejohet të kryejë këtë veprim». Përgjigju asaj nga baza juaj e të dhënave të llogarive, jo nga ajo që dërgoi klienti:
id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json
Komanda e tretë është ajo që njerëzit e kalojnë. Nëse skedari objektiv zotërohet nga root sepse e krijoi hook-u i mëparshëm, një veprim përdoruesi i konfiguruar saktë do të dështojë me një gabim leje që duket si problem systemd dhe nuk është.
Daemoni mbetet aty ku është
Ndryshimi i User= të vetë shërbimit VPN në Alice është levë e gabuar. Ndryshon mënyrën se si daemoni lidh ndërfaqet, lexon çelësat, shkruan skedarin e statusit dhe menaxhon rrugët, dhe e zhvendos gjithë atë rrezik në një njësi që funksiononte. Daemoni ka nevojë për privilegjet e tij; veprimi pasues jo.
Shiko çfarë bën vërtet njësia përpara se ta prekësh. Dy komanda të tregojnë identitetin e ekzekutimit dhe rreshtat e saktë të komandës në fuqi, përfshirë gjithçka që ka shtuar një anulim:
systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server
Në një instalim standard pakete daemoni është root dhe skripti --up e trashëgon këtë. Konfirmoje në vend që ta supozosh, sepse një shpërndarje e forcuar mund ta ketë zhvendosur në një llogari të dedikuar, dhe një drop-in i shkruar me dorë mund ta ekzekutojë hook-un përmes një mbështjellësi me rregulla të tjera.
Tre pjesë të emërtuara, një shkaktues i ngushtë
Rregullimi që i mbijeton mirëmbajtjes ka një ngjarje, një shkaktues dhe një veprim. Daemoni raporton se një sesion i emërtuar është ngritur. Një shkaktues e pranon atë fakt të vogël dhe kërkon një veprim të fiksuar. Veprimi ekzekutohet nën llogarinë lokale që zotëron skedarët që prek. Asgjë në zinxhir nuk pranon një shteg komande arbitrar.
Vetë veprimi është një njësi shërbimi e zakonshme, dhe identiteti është një direktivë brenda saj:
[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i
Vini re se User=alice vlen për të gjithë njësinë, dhe systemd dokumenton një përjashtim që ia vlen ta dish: një komandë me prefiksin + ekzekutohet me privilegje të plota pavarësisht kësaj. Ai prefiks është mjet legjitim për një hap të vetëm të privilegjuar dhe një mënyrë e përshtatshme për të anuluar ndarjen që sapo ndërtuat, prandaj trajto çdo + në atë njësi si diçka që duhet arsyetuar në rishikim.
Mbaje hyrjen e shkaktuesit minimale dhe jo të fshehtë. Identifikuesi i sesionit, llogaria e mapuar dhe një vulë kohore janë zakonisht gjithçka që nevojitet. Kurrë mos kalo përtej kufirit një fragment shell, shteg ekzekutuesi ose bllok mjedisi të ofruar nga klienti, sepse pala që pranon nuk ka asnjë mënyrë të dallojë një vlerë legjitime nga një e injektuar.
Verifiko identitetin që ekzekutoi vërtet
Rishikimi i konfigurimit nuk është provë. Pas një lidhjeje testimi të miratuar, konfirmo UID-në që preku skedarin dhe UID-në që daemoni ende përdor:
stat -c '%U %G %y %n' /home/alice/.local/state/vpn-status.json
ps -o user=,pid=,cmd= -p "$(pgrep -o -f 'openvpn --daemon')"
systemd-run --uid=alice --pipe /usr/local/bin/refresh-vpn-status --dry-run
Rreshti i parë duhet të tregojë Alice dhe një vulë kohore brenda dritares së testimit. I dyti duhet të tregojë ende root ose llogarinë e shërbimit të paketës, gjë që provon se daemoni nuk lëvizi. I treti është mënyra më e lirë për të testuar lejet e veprimit pa pritur një rilidhje të vërtetë.
Nëse pronari i skedarit është Alice por grupi ose modaliteti i tij ndryshoi midis ekzekutimeve, kërko një UMask= ose një ndryshim leje drejtorie në vend të një gabimi logjik. Nëse vula kohore nuk lëvizi fare, shkaktuesi nuk u aktivizua kurrë, dhe hapi tjetër i dobishëm është journalctl -u për njësinë e veprimit në vend të një rilidhjeje tjetër të klientit.
Çfarë ende nuk provon një ngjarje lidhjeje
Një tunel i vendosur është një fakt i vetëm. Nuk do të thotë se sesioni i desktopit është i shkyçur, bus-i i sesionit është i arritshëm ose burimi privat që kërkon veprimi është tashmë i disponueshëm. Një njësi oneshot nën UID-në e Alice ka identitetin e saj dhe asgjë nga sesioni i saj, prandaj çdo gjë që kërkon një bus grafik duhet të kalojë përmes mekanizmit të mbështetur të sesionit të përdoruesit dhe të përcaktojë çfarë ndodh kur ajo është e çkyçur.
Rilidhjet gjithashtu përsëriten. Një laptop që fle në një tren mund të prodhojë një duzinë ngjarje lidhjeje në një orë, dhe një hook që shton një rresht çdo herë e kthen një skedar statusi në një regjistër që askush nuk mund ta lexojë. Bëje veprimin idempotent, ose lëre të zëvendësojë një rekord të vetëm me çelës sipas sesionit.
Më në fund, kufizo rrezen e dëmit në vetë njësinë: një pamje vetëm-lexim e sistemit të skedarëve jashtë drejtorisë së statusit, pa privilegje të reja dhe me një afat kohor të qartë. Ndarja midis daemonit dhe veprimit të përdoruesit ia vlen në vetvete, por ia vlen shumë më tepër kur veprimi nuk mund të bëjë asgjë tjetër përveç asaj të vetme që miratuat.