Hoe werkt umask voor bestandsrechten in Linux?
De umask bepaalt de rechten van nieuwe bestanden en mappen. Leer hoe u de octale waarde controleert en begrijp waarom root en uw eigen gebruiker verschillende permissies krijgen.
Wat de umask doet op Linux
De umask is een getal dat door elk proces op Linux wordt gedragen en bepaalt de modus van elk bestand en elke map die het proces aanmaakt. Een programma vraagt de kernel bij het aanmaken om een set rechten. De kernel wist elke bit die in het masker staat en past de rest toe. Een umask verleent nooit toegang. Het verwijdert alleen bits van wat het aanmakende programma heeft aangevraagd.
De waarde is geen eigenschap van uw distributie. Het hangt af van het account dat u gebruikt en van de manier waarop de shell is gestart. Die twee antwoorden kunnen op één machine, op hetzelfde moment, op een standaard image verschillen. De eerste stap is daarom geen opzoekwerk in een handleiding. Het is een meting op de machine die voor u staat.
Het umask weergeven in de huidige shell
umask
umask -SDe eerste vorm geeft het masker weer in octale notatie. De tweede vorm toont hetzelfde masker als de toegestane permissies, in de symbolische notatie die chmod accepteert. Houd beide regels in beeld. Alles hieronder is een vergelijking met wat uw shell zojuist heeft weergegeven.
umask is een shell-builtin en geen programma op de schijf. Bevestig dit met type umask. Dit is van belang, omdat een builtin het shell-proces zelf wijzigt. Een afzonderlijk programma zou alleen zijn eigen proces kunnen wijzigen, waarna het afsluit en de wijziging verloren gaat.
Maak een bestand en een map aan en lees vervolgens de permissies uit
cd "$(mktemp -d)"
touch probe.file
mkdir probe.dir
stat -c '%a %A %n' probe.file probe.dir%a toont de modus in octale notatie en %A toont dezelfde modus in de drwxr-xr-x-vorm die ls -l gebruikt. Vergelijk beide regels met het masker dat u zojuist heeft afgedrukt. Elke bit die in het masker is ingesteld, ontbreekt in de modi, omdat het wissen van die bits de enige functie van een masker is. Als de %A-kolom nog niet duidelijk is, is de drwxr-xr-x permissiereeks het eerste wat u moet begrijpen.
Het bestand en de map verschillen van elkaar, en het masker is niet de oorzaak van dat verschil. touch vraagt de kernel om lees- en schrijfrechten voor de eigenaar, groep en anderen. mkdir vraagt om lees-, schrijf- en uitvoerrechten voor alle drie. Hetzelfde masker wordt afgetrokken van twee verschillende verzoeken. Een bestand dat is aangemaakt met touch is daarom nooit uitvoerbaar, ongeacht wat het masker bevat: de uitvoerbit werd nooit aangevraagd en een masker kan een bit niet toevoegen.
( umask a=rwx; touch open.file; stat -c '%a %A %n' open.file )Deze haakjes voeren de commando's uit in een subshell, waardoor de wijziging verloren gaat zodra deze wordt afgesloten. Het masker vraagt nu om niets te wissen, en stat rapporteert nog steeds geen uitvoerbit op het bestand. Voer daarna opnieuw umask uit en uw oorspronkelijke waarde is terug; dit toont aan dat de instelling binnen een proces leeft en wordt overgeërfd door sub-processen, in plaats van dat deze ergens op schijf wordt opgeslagen.
Bij mappen is het effect van een gewiste uitvoerbit wel merkbaar.
( umask a=rw; mkdir noexec.dir; cd noexec.dir )Als gewone gebruiker faalt cd met bash: cd: noexec.dir: Permission denied, omdat het masker de uitvoerbit die mkdir aanvroeg heeft gewist, en een map zonder uitvoerbit kan niet worden betreden. Root omzeilt deze controle, dus dit gedrag is alleen zichtbaar bij een normaal account.
Waarom root en uw eigen gebruiker een verschillende umask zien
Voer dezelfde meting uit via een ander account, gestart op een andere manier, en vergelijk de twee uitvoerwaarden naast elkaar.
umask
sudo -i umasksudo -i start de login-shell van root en voert de builtin daarin uit; dit is dus een ander account dat via een ander opstartpad binnenkomt. Op standaard Ubuntu- en Debian-serverimages kunnen de twee regels verschillende waarden weergeven. Beide regels zijn correct. Elke regel toont wat het eigen opstartpad heeft gegenereerd, en de rest van dit bericht gaat over welk deel van het systeem dit heeft geproduceerd.
Welk bestand op uw image bepaalde de waarde
grep -nE '^(UMASK|USERGROUPS_ENAB)' /etc/login.defs
grep -rn pam_umask /etc/pam.d/
grep -rn umask /etc/profile /etc/profile.d/ /etc/bash.bashrc ~/.profile ~/.bashrc 2>/dev/null || echo 'no umask line in the shell startup files'Als de eerste grep niets weergeeft, voer deze dan opnieuw uit zonder het ^-anker: de regel kan zijn uitgeschreven als commentaar, en een regel met commentaar is documentatie in plaats van configuratie. De derde grep is degene die mensen vaak verrast. Op Debian en Ubuntu verwijst het meegeleverde /etc/profile meestal naar PAM in plaats van zelf een mask in te stellen, waardoor het bestand waarvan u aannam dat het verantwoordelijk was, dat vaak niet is. grep sluit af met een non-zero status wanneer het geen overeenkomst vindt, en daarom eindigt die regel op || echo: op een image waar geen enkel opstartbestand een mask vermeldt, krijgt u de melding in plaats van stilte, en de melding is de bevinding.
/etc/login.defs adverteert een waarde en PAM past er een toe
De UMASK-regel in /etc/login.defs is de waarde die in de meeste handleidingen wordt genoemd. Noch de kernel, noch de shell leest dat bestand. Het wordt gelezen door pam_umask, een PAM-module (pluggable authentication modules) die wordt uitgevoerd wanneer een sessie wordt aangemaakt. pam_umask neemt de eerste waarde die het vindt: een umask=-vermelding in het GECOS-veld van de gebruiker, vervolgens een umask=-argument dat op de pam_umask.so-regel zelf staat, en daarna UMASK uit /etc/login.defs. Distributies passen deze module aan, dus voer man pam_umask uit op uw eigen image en lees de volgorde die daar wordt weergegeven.
Dat is hoe /etc/login.defs de ene waarde kan adverteren terwijl uw sessie met een andere eindigt, zonder dat er aan beide kanten een waarschuwing wordt gegeven. De grep-opdrachten vertellen u in welk scenario u zich bevindt. Als de pam_umask.so-regel een eigen umask=-argument bevat, dan is de waarde in login.defs niet van kracht.
USERGROUPS_ENAB en de root-uitzondering
id -un
id -gnAls deze twee dezelfde naam weergeven, gebruikt u een user private group: het account is aangemaakt met een eigen groep die dezelfde naam draagt. pam_umask heeft een usergroups-gedrag, dat wordt beheerd door USERGROUPS_ENAB in /etc/login.defs. Wanneer dit is ingeschakeld, en het account niet root is, en de primaire groepsnaam overeenkomt met de gebruikersnaam, kopieert de module het eigenaar-cijfer van het mask naar het groeps-cijfer. De sessie eindigt dan met een mask dat de groepsbits openstelt voor alles wat dat account aanmaakt. Root wordt door de module zelf uitgesloten, en die uitsluiting is de meest voorkomende reden waarom twee shells op één server verschillende masks weergeven.
De redenering achter deze regel is dat een private group precies één lid heeft, waardoor schrijfbaar voor de groep hetzelfde betekent als schrijfbaar voor de eigenaar. Dat blijft zo totdat iemand een tweede lid aan de groep toevoegt. Vanaf dat moment is elk bestand dat het account ooit heeft aangemaakt schrijfbaar voor het nieuwe lid, zonder dat er een commando op die bestanden is uitgevoerd om dat te bewerkstelligen. Geef elke service een eigen user account met minimale rechten en die groep blijft bewust een groep van één.
Login shell, non-login shell en non-interactive shell
umask
bash -lc 'umask'
bash -c 'umask'PAM wordt uitgevoerd wanneer een sessie wordt aangemaakt: login op de console, sshd, su, sudo -i. Het wordt niet uitgevoerd wanneer een shell een andere shell start. bash -l is een login shell, dus deze leest /etc/profile en ~/.profile, maar roept nooit pam_umask aan omdat er geen sessie werd aangemaakt. bash -c leest geen van beide bestanden en neemt het masker over van het proces dat de shell startte. Een cron job, een git hook en een programma dat door een service manager wordt gestart, vallen allemaal onder dit laatste geval; hun masker is dus gelijk aan dat van hun ouderproces.
Dit is de reden waarom "Ik heb het ingesteld in /etc/profile en de service schrijft nog steeds met de verkeerde modus" zo'n veelvoorkomende melding is. De service heeft dat bestand nooit gelezen.
Waar u dit instelt zodat het behouden blijft
Stel het masker in op de plek waar de workload daadwerkelijk start, omdat elk opstartpad een ander bestand leest.
- Voor accounts die inloggen:
UMASKin/etc/login.defs, toegepast door pam_umask op elke sessie op de machine. Dit is machinebreed, dus het wijzigt alle accounts tegelijk. - Voor één account: het
umask=-argument op depam_umask.so-regel is ook machinebreed, dus een waarde per gebruiker hoort in het GECOS-veld van die gebruiker, of in~/.profilevoor login-shells en~/.bashrcvoor interactieve shells. - Voor een daemon onder systemd:
UMask=in de[Service]-sectie van de unit. Een unit wordt gestart door de service manager, dus/etc/profilewordt nooit gelezen en pam_umask wordt nooit uitgevoerd. Het unit-bestand is het enige van deze lijst dat de daemon bereikt. - Voor een script dat wordt gestart door cron of een hook: een expliciet
umaskop de eerste regel, voordat het script iets aanmaakt.
[Service]
UMask=<the octal mask you chose>Controleer het vervolgens vanaf een nieuwe start van datzelfde pad, en nooit vanuit de shell waarin u het bestand heeft bewerkt. Uw huidige shell behoudt zijn eigen masker, en het bewerken van een configuratiebestand heeft geen invloed op een draaiend proces.
bash -lc 'umask'
sudo -i umaskWaarom chmod achteraf niet dezelfde oplossing is
chmod herstelt bestanden die al bestaan. Het umask bepaalt de modus van bestanden die nog niet bestaan. Voer chmod -R uit op een map en het volgende bestand dat de service schrijft, krijgt weer de oude modus, omdat die modus afkomstig is van het proces dat het bestand aanmaakt en niets aan de map dit wijzigt.
Er is ook een tijdsvenster. Tussen het moment dat een bestand wordt aangemaakt en het moment dat chmod wordt uitgevoerd, staat het bestand op de schijf met de ruimere modus, en elk proces dat de map kan lezen, kan het bestand openen. Voor een privésleutel of een back-uparchief is dat venster het risico dat u probeerde weg te nemen.
Stel de modus in bij het aanmaken. install -m u=rw,go= newfile /etc/app/newfile schrijft de bestemming met een expliciete modus, en mkdir -m doet hetzelfde voor een map. Beide gebruiken de modus die u opgeeft en negeren het umask. ssh-keygen stelt de modus in op de privésleutel die het schrijft; daarom is dat ene bestand vaak wel correct op een machine waar de rest dat niet is.
Het gebruikelijke slachtoffer is SSH. Een ~/.ssh die is aangemaakt met een simpel mkdir, of een authorized_keys waaraan is toegevoegd met cat >>, neemt het umask van uw shell over. Met StrictModes ingeschakeld, weigert sshd een sleutelbestand te lezen uit een map die schrijfbaar is voor de groep. De client krijgt de melding Permission denied (publickey), terwijl de /var/log/auth.log van de server de werkelijke oorzaak vastlegt:
Authentication refused: bad ownership or modes for directory /home/deploy/.sshDie controle is bewust, en het beveiligen van SSH op een VPS is ervan afhankelijk dat deze standhoudt. Meet het umask op een nieuwe server voordat u de accounts aanmaakt die het zullen gebruiken, in combinatie met de eerste tien minuten op een nieuwe VPS, zodat de modus van elk bestand dat die accounts schrijven vooraf is vastgelegd.
Kopieën en archieven negeren het masker
cp -p en rsync -a herstellen de modus zoals die op het bronbestand is vastgelegd, waardoor het masker geen invloed heeft op het resultaat. tar doet hetzelfde bij het uitpakken als root, of als een gewone gebruiker met -p. Een bestand dat vanuit een back-up wordt teruggezet, behoudt de modus die het had op het moment dat de back-up werd gemaakt. Controleer dit voordat u concludeert dat een correct masker wordt genegeerd: voor teruggezette gegevens is het masker nooit geraadpleegd.
FAQ
Waarom maakt mijn cron job bestanden aan met andere rechten dan mijn ssh-sessie?
Een cron job is geen login-sessie, dus pam_umask wordt niet uitgevoerd en het leest noch /etc/profile, noch ~/.profile. Het erft het masker van het proces dat het heeft gestart. Plaats een expliciete umask op de eerste regel van het script, voordat er bestanden worden aangemaakt, en laat het masker eenmaal printen vanuit de job zodat u kunt zien wat die job daadwerkelijk gebruikt in plaats van wat uw eigen shell gebruikt.
Waarom zegt /etc/login.defs iets anders dan wat mijn shell weergeeft?
UMASK in /etc/login.defs is slechts de laatste terugvaloptie voor pam_umask. De module geeft de voorkeur aan een umask=-vermelding in het GECOS-veld van de gebruiker, gevolgd door een umask=-argument op de pam_umask.so-regel in /etc/pam.d/. Het usergroups-gedrag, ingeschakeld via USERGROUPS_ENAB, overschrijft vervolgens het groepsgetal voor elk niet-root account waarvan de primaire groep dezelfde naam heeft als de gebruiker. Voer grep -rn pam_umask /etc/pam.d/ en id -un; id -gn uit om te zien welke van deze opties van toepassing is op uw account.
Kan een umask een bestand uitvoerbaar maken?
Nee. Een masker kan alleen bits verwijderen van wat het aanmakende programma heeft aangevraagd. touch vraagt nooit om de uitvoerbare bit, dus geen enkel masker produceert een uitvoerbaar bestand. Controleer dit in een tijdelijke map met ( umask a=rwx; touch f; stat -c '%a %A' f ). Om een uitvoerbare bit te verkrijgen heeft u chmod nodig, of een programma zoals install -m dat hierom vraagt tijdens het aanmaken.
Waar stel ik het umask in voor een systemd-service?
In de unit, met UMask= in de sectie [Service]. Een service wordt gestart door de service manager in plaats van door een login, dus de shell-opstartbestanden worden nooit gelezen en pam_umask wordt niet uitgevoerd. Na systemctl daemon-reload en een herstart van de unit, controleert u dit van buitenaf: laat de service een bestand aanmaken en lees het resultaat met stat -c '%a %n'.
Is een standaardmasker met schrijfrechten voor de groep veilig?
Dit is veilig zolang de groep uit precies één lid bestaat, wat de aanname is achter het systeem van private gebruikersgroepen. Voeg een tweede account toe aan die groep en elk bestand dat het eerste account heeft aangemaakt, wordt direct schrijfbaar voor het nieuwe lid, zonder dat er een commando op die bestanden hoeft te worden uitgevoerd. Voer id -un en id -gn uit: als dezelfde naam wordt geprint, betekent dit dat u in een private groep zit. Als u een groep deelt tussen accounts, stel dan een masker in dat de schrijfrecht-bit voor de groep verwijdert, maak vervolgens een bestand aan en lees stat -c '%a %n' om te verifiëren dat de wijziging effect heeft gehad.