SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor

Как работает umask в Linux: настройка прав доступа

Узнайте, как umask ограничивает права при создании файлов и каталогов. В статье приведено практическое руководство по проверке маски и объяснение различий между root и пользователем.

Что делает umask в Linux

Umask — это число, которое несет в себе каждый процесс в Linux. Оно определяет права доступа для каждого файла и каталога, создаваемого этим процессом. Программа запрашивает у ядра набор прав в момент создания объекта. Ядро сбрасывает все биты, указанные в маске, и применяет оставшиеся. Umask никогда не предоставляет доступ. Она только отнимает биты у тех прав, которые запросила создающая программа.

Это значение не является свойством вашего дистрибутива. Оно зависит от того, под какой учетной записью вы работаете и как была запущена оболочка (shell). Эти два параметра могут отличаться на одной машине, в один и тот же момент времени, даже на стандартном образе системы. Поэтому первым шагом должен быть не поиск в руководстве, а проверка текущего значения на сервере, с которым вы работаете.

Вывод 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 )

Эти круглые скобки запускают команды в подоболочке (subshell), поэтому изменения исчезают вместе с ней. Теперь маска не требует сброса никаких битов, но 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 не запускается, когда одна оболочка (shell) запускает другую. 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-оболочек и ~/.bashrc для интерактивных оболочек.
  3. Для демона под управлением systemd: UMask= в секции [Service] юнита. Юнит запускается менеджером сервисов, поэтому /etc/profile не считывается, а pam_umask не выполняется. Файл юнита — единственный из перечисленных, который влияет на демона.
  4. Для скрипта, запускаемого через cron или хук: явная команда umask в первой строке, до того как скрипт создаст какие-либо объекты.
[Service]
UMask=<the octal mask you chose>

Затем выполните проверку после чистого запуска по тому же пути, а не из той оболочки, где вы редактировали файл. Ваша текущая оболочка уже сохранила свою маску, и редактирование конфигурационного файла не влияет на уже запущенный процесс.

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, и права доступа для каждого файла, создаваемого этими учетными записями, будут определены заранее.

Копирование и архивация игнорируют маску

cp -p и rsync -a восстанавливают права доступа, зафиксированные в исходном файле, поэтому маска не влияет на результат. tar делает то же самое при извлечении данных от имени root или обычного пользователя с флагом -p. Файл, восстановленный из резервной копии, сохраняет права, которые были у него на момент создания копии. Убедитесь в этом, прежде чем делать вывод, что корректная маска игнорируется: для восстановленных данных она никогда не учитывалась.

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-сервиса?

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

Безопасна ли маска по умолчанию с правами на запись для группы?

Это безопасно, пока в группе только один участник — именно на этом основана схема частных групп пользователей (user private group). Добавьте вторую учетную запись в эту группу, и все файлы, созданные первым пользователем, мгновенно станут доступны для записи новому участнику без выполнения каких-либо команд над этими файлами. Выполните id -un и id -gn: если выводится одно и то же имя, значит, вы используете частную группу. Если вы используете общую группу для нескольких учетных записей, установите маску, которая сбрасывает бит записи для группы, затем создайте файл и проверьте stat -c '%a %n', чтобы убедиться, что изменения вступили в силу.

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