VPN-daemonin yhteys-hookit ajetaan daemonina, ja yleensä se tarkoittaa, että ne ajetaan rootina. Heti kun yksi näistä hookeista kirjoittaa jonkun kotihakemistoon tai käynnistää työpöytäavustajan uudelleen, olet antanut verkkotapahtumalle kyvyn toimia mielivaltaisena paikallisena käyttäjänä. Tavallinen oikotie, käyttäjänimen lukeminen ympäristömuuttujasta ja sen välittäminen eteenpäin, ei korjaa tätä. Se nimeää toiminnon uudelleen muuttamatta sitä, mikä tili sen suorittaa. Se, mikä toimii, on kolmiosainen luovutus, jossa etuoikeutettu vaihe kertoo mitä tapahtui ja erillinen yksikkö suorittaa toiminnon oikealla identiteetillä.

Käyttäjänimi ympäristössä ei ole identiteettikytkin

Unix päättää, mihin prosessi saa koskea, tehokkaan käyttäjätunnuksensa perusteella, ei ympäristönsä merkkijonojen perusteella. USER=alice asettaminen tai LOGNAME vieminen muuttaa sitä, mitä huolimaton ohjelmisto tulostaa lähtöönsä; se ei muuta mitään tiedostojen omistajuuden tarkistuksissa. Rootina ajettava hook, jolla tämä muuttuja on asetettu, avaa yhä Alicen tiedostot rootina.

Nimetkään eivät ole sama nimi. Etäkäytön kirjautuminen, paikallinen Unix-tili ja varmenteen yleinen nimi ovat kolme tunnistetta, jotka usein osuvat yhteen ja joskus eivät. Käyttäjällä, joka todentaa itsensä muodossa a.smith, ei välttämättä ole lainkaan paikallista tiliä, tai se voi kuvautua muotoon asmith hakemistopalvelun kautta. Mikä tahansa suunnittelu, joka olettaa yhden merkkijonon palvelevan kaikkia kolmea roolia, hajoaa ensimmäisen urakoitsijan kohdalla.

Ensimmäinen kysymys ei siis ole ”mikä käyttäjä on yhdistetty” vaan ”millä paikallisella tilillä on lupa suorittaa tämä toiminto”. Vastaa siihen omasta tilitietokannastasi, älä siitä, mitä asiakas lähetti:

id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json

Kolmas komento on se, jonka ihmiset ohittavat. Jos kohdetiedoston omistaa root, koska edellinen hook loi sen, oikein määritetty käyttäjätoiminto epäonnistuu käyttöoikeusvirheeseen, joka näyttää systemd-ongelmalta eikä ole sitä.

Daemon pysyy siellä missä on

VPN-palvelun oman User=-asetuksen vaihtaminen Aliceksi on väärä vipu. Se muuttaa sitä, miten daemon sitoo rajapinnat, lukee avaimet, kirjoittaa tilatiedostonsa ja hallitsee reitit, ja se siirtää kaiken tämän riskin yksikköön, joka toimi. Daemon tarvitsee etuoikeutensa; jälkitoiminto ei.

Katso, mitä yksikkö todella tekee ennen kuin kosket siihen. Kaksi komentoa kertovat suoritusidentiteetin ja täsmälliset voimassa olevat komentorivit, mukaan lukien kaikki mitä ohitus on lisännyt:

systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server

Oletusarvoisessa paketticasennuksessa daemon on root ja --up-skripti perii sen. Vahvista se sen sijaan että olettaisit, koska kovennettu jakelu on voinut siirtää sen omalle tilille, ja käsin kirjoitettu drop-in voi ajaa hookin kääreen kautta, jolla on eri säännöt.

Kolme nimettyä osaa, yksi kapea liipaisin

Järjestely, joka kestää ylläpitoa, sisältää tapahtuman, liipaisimen ja toiminnon. Daemon ilmoittaa, että nimetty istunto nousi. Liipaisin hyväksyy tämän pienen tosiasian ja pyytää yhtä kiinteää toimintoa. Toiminto ajetaan sen paikallisen tilin alla, joka omistaa sen koskemat tiedostot. Mikään ketjussa ei hyväksy mielivaltaista komentopolkua.

Toiminto itsessään on tavallinen palveluyksikkö, ja identiteetti on yksi direktiivi sen sisällä:

[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i

Huomaa, että User=alice koskee koko yksikköä, ja systemd dokumentoi yhden poikkeuksen, joka kannattaa tuntea: komennolla, jonka etuliite on +, ajetaan täysin etuoikeuksin siitä riippumatta. Tämä etuliite on laillinen työkalu yhteen etuoikeutettuun vaiheeseen ja kätevä tapa kumota juuri rakentamasi erottelu, joten käsittele mitä tahansa +-merkintää kyseisessä yksikössä asiana, joka on perusteltava katselmoinnissa.

Pidä liipaisimen syöte minimaalisena ja ei-salaisena. Istunnon tunniste, kuvattu tili ja aikaleima ovat yleensä kaikki mitä tarvitaan. Älä koskaan välitä rajan yli shell-fragmenttia, suoritettavan tiedoston polkua tai asiakkaan toimittamaa ympäristölohkoa, koska vastaanottava puoli ei voi erottaa laillista arvoa injektoidusta.

Varmista identiteetti, joka todella ajettiin

Määritysten katselmointi ei ole todiste. Hyväksytyn testiyhteyden jälkeen varmista UID, joka koski tiedostoa, ja UID, jota daemon yhä käyttää:

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

Ensimmäisen rivin pitäisi näyttää Alice ja aikaleima testi-ikkunasi sisällä. Toisen pitäisi näyttää yhä root tai paketin palvelutili, mikä todistaa, ettei daemon liikkunut. Kolmas on halvin tapa testata toiminnon käyttöoikeudet odottamatta todellista uudelleenyhdistämistä.

Jos tiedoston omistaja on Alice mutta sen ryhmä tai tila muuttui ajojen välillä, etsi UMask= tai hakemiston käyttöoikeusero logiikkavirheen sijaan. Jos aikaleima ei liikkunut lainkaan, liipaisin ei lauennut koskaan, ja hyödyllinen seuraava askel on journalctl -u toimintoyksikölle eikä uusi asiakkaan uudelleenyhdistäminen.

Mitä yhteystapahtuma ei vieläkään todista

Muodostettu tunneli on yksi tosiasia. Se ei tarkoita, että työpöytäistunto on avattu, istuntoväylä on tavoitettavissa tai toiminnon haluama yksityinen resurssi on jo saatavilla. Alicen UID:n alla olevalla oneshot-yksiköllä on hänen identiteettinsä eikä mitään hänen istunnostaan, joten kaiken graafisen väylän vaativan on mentävä tuetun käyttäjäistuntomekanismin kautta ja määriteltävä, mitä tapahtuu kun hän on kirjautunut ulos.

Uudelleenyhdistämiset myös toistuvat. Junassa nukkuva kannettava voi tuottaa tusinan yhteystapahtumia tunnissa, ja hook, joka lisää rivin joka kerta, muuttaa tilatiedoston lokiksi, jota kukaan ei voi lukea. Tee toiminnosta idempotentti tai anna sen korvata yksi istunnolla avaimistettu tietue.

Rajoita lopuksi vahinkosäde itse yksikössä: vain luku -näkymä tiedostojärjestelmään tilahakemiston ulkopuolella, ei uusia etuoikeuksia ja nimenomainen aikakatkaisu. Daemonin ja käyttäjätoiminnon erottelu on itsessään arvokasta, mutta se on paljon arvokkaampaa, kun toiminto ei voi tehdä mitään muuta kuin sen yhden asian, jonka hyväksyit.

Aiheeseen liittyvät artikkelit