SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor

Jak działa umask w Linux: uprawnienia plików i katalogów

Dowiedz się, jak umask wpływa na domyślne uprawnienia tworzonych plików. Sprawdź bieżącą wartość, porównaj wyniki dla roota i użytkownika oraz zrozum działanie maski bitowej.

Działanie umask w systemie Linux

Wartość umask jest liczbą przypisaną do każdego procesu w systemie Linux, która określa tryb dostępu dla każdego pliku i katalogu tworzonego przez ten proces. Program w momencie tworzenia obiektu żąda od jądra określonego zestawu uprawnień. Jądro usuwa wszystkie bity wskazane w masce i stosuje pozostałe. Umask nigdy nie nadaje uprawnień. Służy jedynie do odbierania bitów z uprawnień żądanych przez tworzący program.

Wartość ta nie jest właściwością dystrybucji. Zależy ona od używanego konta oraz sposobu uruchomienia powłoki. Te dwa czynniki mogą się różnić na tej samej maszynie, w tym samym momencie, nawet w przypadku standardowego obrazu systemu. Dlatego pierwszym krokiem nie jest przeglądanie dokumentacji, lecz dokonanie pomiaru na obsługiwanym serwerze.

Wyświetlanie wartości umask w bieżącej powłoce

umask
umask -S

Pierwsza postać polecenia wyświetla maskę w formacie ósemkowym. Druga postać wyświetla tę samą maskę w formie symbolicznej, akceptowanej przez chmod. Pozostaw obie linie widoczne na ekranie. Wszystkie poniższe informacje stanowią porównanie z wartościami zwróconymi przez powłokę.

umask jest wbudowanym poleceniem powłoki, a nie plikiem wykonywalnym na dysku. Potwierdź to za pomocą type umask. Jest to istotne, ponieważ polecenie wbudowane modyfikuje proces samej powłoki. Osobny program mógłby zmienić jedynie własny proces, po czym zakończyć działanie, tracąc wprowadzone zmiany.

Utworzenie pliku i katalogu oraz odczyt ich trybów

cd "$(mktemp -d)"
touch probe.file
mkdir probe.dir
stat -c '%a %A %n' probe.file probe.dir

%a wyświetla tryb w formacie ósemkowym, a %A wyświetla ten sam tryb w postaci drwxr-xr-x, której używa ls -l. Porównaj obie linie z maską wyświetloną przed chwilą. Każdy bit ustawiony w masce jest nieobecny w trybach, ponieważ wyzerowanie tych bitów jest jedyną funkcją maski. Jeśli kolumna %A nie jest jeszcze czytelna, ciąg uprawnień drwxr-xr-x jest elementem, który należy najpierw zrozumieć.

Plik i katalog różnią się od siebie, a maska nie jest przyczyną tej różnicy. touch żąda od jądra uprawnień do odczytu i zapisu dla właściciela, grupy oraz pozostałych użytkowników. mkdir żąda uprawnień do odczytu, zapisu i wykonywania dla wszystkich trzech kategorii. Ta sama maska jest odejmowana od dwóch różnych żądań. Dlatego plik utworzony przez touch nigdy nie jest wykonywalny, niezależnie od zawartości maski: bit wykonywania nigdy nie został zażądany, a maska nie może przywrócić bitu.

( umask a=rwx; touch open.file; stat -c '%a %A %n' open.file )

Nawiasy uruchamiają polecenia w podpowłoce, więc zmiana kończy się wraz z nią. Maska nie żąda teraz wyzerowania żadnych uprawnień, a stat nadal raportuje brak bitu wykonywania dla pliku. Uruchom ponownie umask, aby przywrócić pierwotną wartość; pokazuje to, że ustawienie żyje wewnątrz procesu i jest dziedziczone przez procesy potomne, zamiast być przechowywanym na dysku.

W przypadku katalogów brak bitu wykonywania jest odczuwalny.

( umask a=rw; mkdir noexec.dir; cd noexec.dir )

Dla zwykłego użytkownika polecenie cd kończy się błędem bash: cd: noexec.dir: Permission denied, ponieważ maska wyzerowała bit wykonywania, o który prosiło mkdir, a do katalogu bez bitu wykonywania nie można wejść. Użytkownik root pomija to sprawdzenie, więc ten efekt jest widoczny tylko na zwykłym koncie.

Dlaczego root i użytkownik końcowy widzą różne wartości umask

Uruchom ten sam pomiar na innym koncie, zainicjowanym w inny sposób, a następnie porównaj oba wyniki.

umask
sudo -i umask

sudo -i uruchamia powłokę logowania użytkownika root i wykonuje w niej wbudowane polecenie, więc jest to inne konto, które korzysta z innej ścieżki inicjacji. W standardowych obrazach serwerowych Ubuntu i Debian obie linie mogą wyświetlać różne wartości. Obie wartości są poprawne. Każda z nich pokazuje wynik wygenerowany przez własną ścieżkę startową, a dalsza część tego wpisu wyjaśnia, która część systemu odpowiada za ten wynik.

Który plik w obrazie określa tę wartość

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'

Jeśli pierwsze polecenie grep nie zwraca wyników, należy uruchomić je ponownie bez znacznika ^: linia może być zakomentowana, a zakomentowana linia stanowi dokumentację, a nie konfigurację. Trzecie polecenie grep jest tym, które często zaskakuje. W systemach Debian i Ubuntu dostarczany plik /etc/profile zazwyczaj wskazuje na PAM zamiast samodzielnie ustawiać maskę, więc plik, który uznano za odpowiedzialny, często nim nie jest. Polecenie grep kończy działanie z kodem wyjścia innym niż zero, gdy nie znajdzie dopasowania, dlatego ta linia kończy się ciągiem || echo: w obrazie, w którym żaden plik startowy nie wspomina o masce, wyświetlany jest komunikat zamiast braku danych, a ten komunikat stanowi wynik poszukiwań.

/etc/login.defs deklaruje wartość, a PAM stosuje inną

Wiersz UMASK w pliku /etc/login.defs zawiera wartość najczęściej cytowaną w poradnikach. Ani jądro, ani powłoka nie odczytują tego pliku. Odczytuje go pam_umask, moduł PAM (pluggable authentication modules), który uruchamia się podczas tworzenia sesji. pam_umask przyjmuje pierwszą napotkaną wartość: wpis umask= w polu GECOS użytkownika, następnie argument umask= zapisany w samym wierszu pam_umask.so, a na końcu UMASK z pliku /etc/login.defs. Dystrybucje modyfikują ten moduł, dlatego należy uruchomić man pam_umask na własnym obrazie systemu i sprawdzić wyświetloną tam kolejność.

W ten sposób /etc/login.defs może deklarować jedną wartość, podczas gdy sesja kończy z inną, bez żadnego ostrzeżenia po obu stronach. Polecenia grep pozwalają ustalić, z którym przypadkiem mamy do czynienia. Jeśli wiersz pam_umask.so zawiera własny argument umask=, wartość z login.defs zostaje nadpisana.

USERGROUPS_ENAB oraz wyjątek dla root

id -un
id -gn

Jeśli oba polecenia zwracają tę samą nazwę, oznacza to użycie prywatnej grupy użytkownika: konto zostało utworzone z własną grupą o takiej samej nazwie. Moduł pam_umask posiada zachowanie usergroups, sterowane przez USERGROUPS_ENAB w pliku /etc/login.defs. Gdy jest ono włączone, a konto nie jest kontem root i nazwa grupy głównej odpowiada nazwie użytkownika, moduł kopiuje cyfrę właściciela z maski do cyfry grupy. Sesja kończy się maską, która pozostawia bity grupy otwarte dla wszystkich plików tworzonych przez to konto. Użytkownik root jest wykluczony przez sam moduł i to wykluczenie jest najczęstszą przyczyną, dla której dwie powłoki na tym samym serwerze wyświetlają różne maski.

Uzasadnieniem tej zasady jest fakt, że prywatna grupa posiada dokładnie jednego członka, więc uprawnienie do zapisu dla grupy oznacza to samo, co uprawnienie dla właściciela. Sytuacja ta trwa do momentu dodania drugiego członka do grupy. Od tego momentu każdy plik utworzony wcześniej przez to konto staje się zapisywalny dla nowego członka, bez konieczności uruchamiania jakiejkolwiek komendy na tych plikach. Należy przypisać każdej usłudze własne konto użytkownika z minimalnymi uprawnieniami, aby grupa celowo pozostała grupą jednoosobową.

Login shell, non-login shell oraz non-interactive shell

umask
bash -lc 'umask'
bash -c 'umask'

Moduł PAM uruchamia się w momencie tworzenia sesji: login na konsoli, sshd, su, sudo -i. Nie jest on wywoływany, gdy jedna powłoka uruchamia kolejną. bash -l jest powłoką logowania (login shell), więc odczytuje pliki /etc/profile oraz ~/.profile, jednak nigdy nie wywołuje pam_umask, ponieważ sesja nie została utworzona. bash -c nie odczytuje żadnego z tych plików i dziedziczy maskę procesu nadrzędnego. Zadania cron, hooki git oraz programy uruchamiane przez menedżer usług należą do tej ostatniej kategorii, dlatego ich maska jest tożsama z maską procesu rodzica.

Jest to powód, dla którego zgłoszenie „ustawiłem to w /etc/profile, a usługa nadal zapisuje pliki z błędnymi uprawnieniami” jest tak częste. Usługa nigdy nie odczytała tego pliku.

Gdzie wprowadzić ustawienia, aby były trwałe

Maskę należy ustawić w miejscu, w którym faktycznie uruchamiane jest zadanie, ponieważ każda ścieżka startowa odczytuje inny plik.

  1. Dla kont logujących się: UMASK w /etc/login.defs, stosowane przez pam_umask do każdej sesji na maszynie. Jest to ustawienie globalne, więc wpływa na wszystkie konta jednocześnie.
  2. Dla jednego konta: argument umask= w linii pam_umask.so również ma zasięg globalny, dlatego wartość dla konkretnego użytkownika powinna znaleźć się w polu GECOS tego użytkownika lub w ~/.profile dla powłok logowania oraz ~/.bashrc dla powłok interaktywnych.
  3. Dla demona zarządzanego przez systemd: UMask= w sekcji [Service] jednostki. Jednostka jest uruchamiana przez menedżer usług, więc /etc/profile nigdy nie jest odczytywane, a pam_umask nie jest wywoływane. Plik jednostki jest jedynym z wymienionych, który ma wpływ na demona.
  4. Dla skryptu uruchamianego przez cron lub hook: jawne umask w pierwszej linii, przed utworzeniem jakiegokolwiek obiektu przez skrypt.
[Service]
UMask=<the octal mask you chose>

Następnie należy zweryfikować ustawienia po świeżym uruchomieniu danej ścieżki, a nie z poziomu powłoki, w której edytowano plik. Bieżąca powłoka posiada już własną maskę, a edycja pliku konfiguracyjnego nie wpływa na działający proces.

bash -lc 'umask'
sudo -i umask

Dlaczego chmod nie jest właściwym rozwiązaniem

chmod naprawia istniejące pliki. Maska decyduje o uprawnieniach plików, które jeszcze nie powstały. Uruchomienie chmod -R w katalogu sprawia, że kolejny plik zapisany przez usługę ponownie otrzyma stare uprawnienia, ponieważ wynikają one z procesu tworzenia, a zmiana uprawnień katalogu nie wpływa na ten mechanizm.

Istnieje również problem czasowy. W okresie między utworzeniem pliku a uruchomieniem chmod, plik znajduje się na dysku z szerszymi uprawnieniami i każdy proces mający dostęp do odczytu katalogu może go otworzyć. W przypadku klucza prywatnego lub archiwum kopii zapasowej, ten czas oczekiwania stanowi ryzyko, które próbowano wyeliminować.

Zamiast tego należy ustawić uprawnienia w momencie tworzenia. install -m u=rw,go= newfile /etc/app/newfile zapisuje plik docelowy z określonymi uprawnieniami, a mkdir -m robi to samo dla katalogu. Oba polecenia przyjmują wskazany tryb i ignorują maskę. ssh-keygen ustawia uprawnienia dla zapisywanego klucza prywatnego, dlatego ten konkretny plik jest często poprawny, podczas gdy inne nie.

Typową ofiarą jest SSH. Plik ~/.ssh utworzony za pomocą zwykłego mkdir lub authorized_keys dopisany przez cat >>, przejmuje maskę powłoki. Przy włączonym StrictModes, sshd odmawia odczytu pliku klucza z katalogu, do którego grupa ma uprawnienia zapisu. Klient otrzymuje komunikat Permission denied (publickey), podczas gdy /var/log/auth.log serwera rejestruje rzeczywistą przyczynę:

Authentication refused: bad ownership or modes for directory /home/deploy/.ssh

Ta kontrola jest celowa, a zabezpieczanie SSH na VPS zależy od jej utrzymania. Należy sprawdzić maskę na nowym serwerze przed utworzeniem kont, które będą z niej korzystać, równolegle z pierwszymi dziesięcioma minutami na nowym VPS, dzięki czemu uprawnienia każdego pliku zapisanego przez te konta będą ustalone z góry.

Kopie i archiwa ignorują maskę

cp -p oraz rsync -a przywracają uprawnienia zapisane w pliku źródłowym, więc maska nie wpływa na wynik. tar zachowuje się tak samo podczas wypakowywania jako root lub jako zwykły użytkownik z flagą -p. Plik przywrócony z kopii zapasowej zachowuje uprawnienia, które posiadał w momencie tworzenia kopii. Należy to sprawdzić przed stwierdzeniem, że poprawna maska jest ignorowana: w przypadku przywracanych danych nigdy nie była ona brana pod uwagę.

FAQ

Dlaczego zadanie cron tworzy pliki z innymi uprawnieniami niż sesja ssh?

Zadanie cron nie jest sesją logowania, więc /etc/profile ani ~/.profile nie są odczytywane, a moduł pam_umask nie jest uruchamiany. Proces dziedziczy maskę po procesie nadrzędnym. Należy umieścić jawne polecenie umask w pierwszej linii skryptu, przed utworzeniem jakichkolwiek plików. Warto również wypisać maskę wewnątrz zadania, aby sprawdzić jej rzeczywistą wartość, zamiast polegać na ustawieniach własnej powłoki.

Dlaczego /etc/login.defs podaje inne wartości niż moja powłoka?

Wartość UMASK w pliku /etc/login.defs stanowi jedynie ostateczne rozwiązanie awaryjne dla modułu pam_umask. Moduł priorytetowo traktuje wpis umask= w polu GECOS użytkownika, a następnie argument umask= w linii pam_umask.so pliku /etc/pam.d/. Mechanizm usergroups, aktywowany przez USERGROUPS_ENAB, nadpisuje cyfrę grupy dla każdego konta innego niż root, którego główna grupa ma taką samą nazwę jak użytkownik. Należy wykonać grep -rn pam_umask /etc/pam.d/ oraz id -un; id -gn, aby sprawdzić, które z tych ustawień ma zastosowanie do danego konta.

Czy umask może nadać plikowi uprawnienia do wykonywania?

Nie. Maska może jedynie usuwać bity z uprawnień żądanych przez program tworzący plik. Polecenie touch nigdy nie żąda bitu wykonywalności, więc żadna maska nie utworzy pliku wykonywalnego. Można to zweryfikować w tymczasowym katalogu za pomocą ( umask a=rwx; touch f; stat -c '%a %A' f ). Aby uzyskać bit wykonywalności, wymagane jest użycie chmod lub programu takiego jak install -m, który żąda tego bitu w momencie tworzenia pliku.

Gdzie ustawić umask dla usługi systemd?

W pliku jednostki, za pomocą dyrektywy UMask= w sekcji [Service]. Usługa jest uruchamiana przez menedżer usług, a nie przez proces logowania, więc pliki startowe powłoki nie są odczytywane, a moduł pam_umask nie jest wywoływany. Po wykonaniu systemctl daemon-reload i restarcie jednostki należy zweryfikować wynik z zewnątrz: pozwolić usłudze utworzyć plik, a następnie sprawdzić jego uprawnienia za pomocą stat -c '%a %n'.

Czy domyślna maska z uprawnieniami zapisu dla grupy jest bezpieczna?

Jest bezpieczna tylko wtedy, gdy grupa posiada dokładnie jednego członka, co stanowi założenie schematu prywatnych grup użytkowników. Dodanie drugiego konta do tej grupy sprawia, że każdy plik utworzony przez pierwsze konto staje się natychmiast zapisywalny dla nowego członka, bez konieczności wykonywania jakichkolwiek poleceń na tych plikach. Należy wykonać id -un oraz id -gn: wyświetlenie tej samej nazwy oznacza korzystanie z grupy prywatnej. W przypadku współdzielenia grupy między kontami należy ustawić maskę usuwającą bit zapisu dla grupy, a następnie utworzyć plik i sprawdzić stat -c '%a %n', aby potwierdzić skuteczność zmiany.

#umask#permissions#pam#login-defs#linux