SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor

umask у Linux: звідки беруться права за замовчуванням

Перевірте umask у поточній оболонці, створіть файл і каталог та порівняйте їхні права. Дізнайтеся, чому root і звичайний користувач отримують різні режими.

Linux у umask

umask — це число, яке має кожен процес у Linux. Воно визначає режим доступу для кожного файла й каталогу, створеного цим процесом. Під час створення програма запитує в ядра набір дозволів. Ядро очищає кожен біт, указаний маскою, і застосовує решту. umask ніколи не надає доступ. Вона лише забирає біти з дозволів, які запросила програма, що створює об’єкт.

Це значення не є властивістю дистрибутива. Воно залежить від облікового запису та способу запуску оболонки. На одному комп’ютері та в один момент ці значення можуть відрізнятися навіть у стандартному образі. Тому перший крок — не пошук у довіднику, а перевірка фактичного значення на потрібному сервері.

Виведіть umask у поточній оболонці

umask
umask -S

Перша форма виводить маску у вісімковому форматі. Друга виводить ту саму маску як дозволи, які вона пропускає, у символьному форматі, прийнятному для chmod. Залиште обидва рядки на екрані. Усе нижче — порівняння з тим, що щойно вивела ваша оболонка.

umask — це вбудована команда оболонки, а не програма на диску. Підтвердьте це за допомогою type umask. Це важливо, оскільки вбудована команда змінює сам процес оболонки. Окрема програма могла б змінити лише власний процес, а потім завершитися та завершити разом із собою цю зміну.

Створіть файл і каталог, а потім зчитайте їхні режими

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

%a виводить режим у вісімковому форматі, а %A виводить той самий режим у форматі drwxr-xr-x, який використовує ls -l. Порівняйте обидва рядки з маскою, яку щойно вивели. Кожен біт, установлений у масці, відсутній у режимах, оскільки маска лише очищає ці біти. Якщо стовпець %A ще важко читати, спочатку розберіться з рядком дозволів drwxr-xr-x.

Файл і каталог відрізняються, і причина не в масці. touch запитує права на читання та запис для власника, групи й інших користувачів. mkdir запитує права на читання, запис і виконання для всіх трьох категорій. Та сама маска застосовується до двох різних запитів. Тому файл, створений за допомогою touch, ніколи не буде виконуваним, незалежно від значення маски: біт виконання не запитувався, а маска не може додати біт назад.

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

Дужки запускають команди в підоболонці, тому зміна зникає разом із нею. Тепер маска не вимагає очищати жодного біта, а stat все одно не показує біта виконання для файлу. Після цього знову виконайте umask — початкове значення повернеться. Це показує, що параметр зберігається всередині процесу й успадковується дочірніми процесами, а не записується на диск.

Для каталогів наслідки очищеного біта виконання помітні особливо чітко.

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

Як звичайний користувач, cd завершується помилкою bash: cd: noexec.dir: Permission denied, оскільки маска очистила біт виконання, який запитував mkdir, а каталог без біта виконання неможливо відкрити. root минає цю перевірку, тому проблема проявляється лише для звичайного облікового запису.

Чому root і ваш користувач бачать різні значення umask

Виконайте те саме вимірювання через інший обліковий запис, запустивши його іншим способом, і порівняйте два результати поруч.

umask
sudo -i umask

sudo -i запускає login shell користувача root і виконує вбудовану команду в ньому. Отже, це інший обліковий запис, який проходить інший шлях запуску. У стандартних образах серверів Ubuntu та Debian ці два рядки можуть вивести різні значення. Обидва рядки правильні. Кожен показує результат свого шляху запуску. У решті цієї статті розглянуто, яка саме частина системи його сформувала.

Який файл у вашому образі визначав це значення

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'

Якщо перший grep нічого не виводить, виконайте його ще раз без якоря ^: рядок може бути закоментований, а закоментований рядок є документацією, а не конфігурацією. Третя команда grep часто дивує. У Debian і Ubuntu встановлений файл /etc/profile переважно посилається на PAM, а не задає маску самостійно, тому файл, який ви вважали відповідальним, часто ним не є. grep завершується з ненульовим кодом, якщо нічого не знаходить, тому цей рядок закінчується на || echo: в образі, де жоден файл запуску не містить маски, ви отримуєте повідомлення, а не порожній вивід, і саме це повідомлення є результатом перевірки.

/etc/login.defs декларує значення, а PAM застосовує інше

Рядок UMASK у /etc/login.defs містить значення, на яке посилається більшість посібників. Ядро та оболонка не читають цей файл. Його читає pam_umask — модуль PAM (pluggable authentication modules), який запускається під час створення сеансу. pam_umask використовує перше знайдене значення: запис umask= у полі GECOS користувача, потім аргумент umask=, указаний безпосередньо в рядку pam_umask.so, і лише потім UMASK із /etc/login.defs. Дистрибутиви вносять зміни до цього модуля, тому виконайте man pam_umask у власному образі та перевірте порядок, виведений командою.

Тому /etc/login.defs може декларувати одне значення, а ваш сеанс отримує інше, причому жодна зі сторін не виводить попередження. Команди grep показують, який саме випадок у вас. Якщо рядок pam_umask.so містить власний аргумент umask=, значення з рядка login.defs не застосовується.

USERGROUPS_ENAB і виняток для root

id -un
id -gn

Якщо ці два значення виводять однакове ім’я, у вас є приватна група користувача: обліковий запис створено із власною групою, названою так само, як і обліковий запис. pam_umask має режим usergroups, яким керує USERGROUPS_ENAB у /etc/login.defs. Коли цей режим увімкнено, обліковий запис не є root, а назва основної групи збігається з іменем користувача, модуль копіює цифру маски для власника в цифру маски для групи. Після цього сеанс завершується з маскою, яка залишає біти групи відкритими для всього, що створює цей обліковий запис. Модуль сам виключає root. Саме це виключення найчастіше пояснює, чому дві оболонки на одному сервері виводять різні маски.

Логіка цього правила полягає в тому, що приватна група має рівно одного учасника. Тому дозвіл на запис для групи означає лише дозвіл на запис для власника. Це працює, доки до групи не додають другого учасника. Від цього моменту новий учасник може записувати в кожен файл, який обліковий запис створив раніше. Для цього не потрібно виконувати жодну команду над цими файлами. Призначайте кожному сервісу власний обліковий запис із мінімальними привілеями, щоб ця група навмисно залишалася групою з одного учасника.

Login shell, non-login shell і non-interactive shell

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

PAM запускається під час створення сеансу: login у консолі, sshd, su, sudo -i. PAM не запускається, коли одна оболонка запускає іншу. bash -l — це login shell, тому вона читає /etc/profile і ~/.profile, але ніколи не викликає pam_umask, оскільки сеанс не створювався. bash -c не читає жоден із цих файлів і успадковує маску процесу, який її запустив. Задане cron-завдання, git hook і програма, запущена менеджером служб, належать до останнього випадку, тому їхня маска визначається маскою батьківського процесу.

Тому повідомлення «Я налаштував це в /etc/profile, але служба й далі записує файли з неправильними правами» трапляється так часто. Служба ніколи не читала цей файл.

Де налаштувати маску, щоб вона зберігалася

Встановлюйте маску там, де фактично запускається робоче навантаження, оскільки кожен спосіб запуску читає інший файл.

  1. Для облікових записів, які виконують вхід: UMASK у /etc/login.defs, що застосовується pam_umask до кожного сеансу на машині. Це загальносистемне налаштування, тому воно змінює значення для всіх облікових записів одночасно.
  2. Для одного облікового запису: аргумент umask= у рядку pam_umask.so також є загальносистемним, тому значення для окремого користувача слід вказати в полі GECOS цього користувача, або в ~/.profile для login shell і в ~/.bashrc для інтерактивних shell.
  3. Для daemon під керуванням systemd: UMask= у секції [Service] unit. Unit запускає service manager, тому /etc/profile ніколи не читається, а pam_umask не запускається. Лише файл unit із наведених варіантів впливає на daemon.
  4. Для скрипту, який запускається cron або hook: явне umask у першому рядку, до того як скрипт створить будь-які об’єкти.
[Service]
UMask=<the octal mask you chose>

Потім перевірте результат після нового запуску тим самим способом і ніколи не перевіряйте його в shell, де ви редагували файл. Поточний shell уже зберігає свою маску, а редагування конфігураційного файлу не змінює вже запущений процес.

bash -lc 'umask'
sudo -i umask

Чому chmod після створення не є таким самим виправленням

chmod виправляє файли, які вже існують. Маска визначає режим файлів, яких ще немає. Виконайте chmod -R для каталогу, і наступний файл, який запише сервіс, знову матиме старий режим, оскільки цей режим походить від процесу, що створює файл, а каталог його не змінює.

Є також часовий проміжок. Від моменту створення файлу до моменту запуску chmod файл перебуває на диску з ширшим режимом доступу, і будь-який процес, який може читати каталог, може його відкрити. Для приватного ключа або архіву резервної копії цей проміжок створює саме той ризик, якого ви намагалися позбутися.

Встановлюйте режим під час створення. install -m u=rw,go= newfile /etc/app/newfile записує файл призначення з явним режимом, а mkdir -m робить те саме для каталогу. Обидві команди використовують вказаний вами режим і ігнорують маску. ssh-keygen встановлює режим для приватного ключа, який записує, тому саме цей файл часто має правильні права на машині, де всі інші файли — ні.

Найчастіше проблема виникає з SSH. Файл ~/.ssh, створений звичайною командою mkdir, або файл authorized_keys, до якого дані додано за допомогою cat >>, успадковує маску вашої оболонки. Якщо увімкнено StrictModes, sshd відмовляється читати файл ключа з каталогу, доступного для запису групі. Клієнт отримує повідомлення Permission denied (publickey), а сервер записує справжню причину в /var/log/auth.log:

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

Ця перевірка виконується навмисно, і посилення захисту SSH на VPS залежить від її коректної роботи. Виміряйте маску на новому сервері до створення облікових записів, які його використовуватимуть, разом із першими десятьма хвилинами на новому VPS, і режим доступу до кожного файлу, який записуватимуть ці облікові записи, буде визначено заздалегідь.

Копіювання й архівування ігнорують mask

cp -p і rsync -a відновлюють режим доступу, записаний для вихідного файла, тому mask не впливає на результат. tar робить те саме під час розпакування від імені root або звичайного користувача з -p. Файл, відновлений із резервної копії, зберігає режим доступу, який він мав на момент створення резервної копії. Перевірте це, перш ніж робити висновок, що правильний mask ігнорують: під час відновлення даних його взагалі не застосовували.

FAQ

Чому моє cron-завдання створює файли з іншим режимом доступу, ніж моя ssh-сесія?

cron-завдання не є сеансом входу, тому pam_umask для нього не запускається, і воно не читає ні /etc/profile, ні ~/.profile. Воно успадковує маску процесу, який його запустив. Додайте явний umask у перший рядок скрипту, до створення будь-яких об’єктів, і один раз виведіть маску безпосередньо із завдання. Так ви побачите фактичну маску цього завдання, а не маску власної оболонки.

Чому /etc/login.defs містить одне значення, а моя оболонка виводить інше?

UMASK у /etc/login.defs є лише останнім резервним значенням для pam_umask. Модуль спочатку використовує запис umask= у полі GECOS користувача, а потім аргумент umask= у рядку pam_umask.so файлу /etc/pam.d/. Поведінка usergroups, яку вмикає USERGROUPS_ENAB, змінює цифру групи для будь-якого облікового запису, крім root, якщо його основна група має таку саму назву, як обліковий запис. Виконайте grep -rn pam_umask /etc/pam.d/ і id -un; id -gn, щоб визначити, яке з цих правил застосовується до вашого облікового запису.

Чи може umask зробити файл виконуваним?

Ні. Маска може лише очистити біти з режиму, який запитала програма, що створює файл. touch ніколи не запитує біт виконання, тому жодна маска не створить виконуваний файл. Перевірте це в тимчасовому каталозі за допомогою ( umask a=rwx; touch f; stat -c '%a %A' f ). Щоб додати біт виконання, потрібен chmod або програма на зразок install -m, яка запитує його під час створення.

Де налаштувати umask для служби systemd?

У unit-файлі, за допомогою UMask= у секції [Service]. Службу запускає менеджер служб, а не сеанс входу, тому файли запуску оболонки не читаються, і pam_umask для неї не запускається. Після systemctl daemon-reload і перезапуску unit-файлу перевірте результат ззовні: дозвольте службі створити файл, а потім прочитайте результат за допомогою stat -c '%a %n'.

Чи безпечна маска за замовчуванням із правом запису для групи?

Це безпечно, доки група має рівно одного учасника. Саме на цьому припущенні ґрунтується схема приватної групи користувача. Якщо додати до цієї групи другий обліковий запис, кожен файл, створений першим обліковим записом, одразу стане доступним для запису новому учаснику без виконання будь-якої команди над цими файлами. Виконайте id -un і id -gn: якщо виводиться те саме ім’я, ви використовуєте приватну групу. Якщо група спільна для кількох облікових записів, налаштуйте маску так, щоб очистити біт запису для групи, потім створіть файл і прочитайте stat -c '%a %n', щоб підтвердити застосування зміни.

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