Добавлен перевод статьи "Dynamic Users with systemd"
This commit is contained in:
685
s4a.tex
685
s4a.tex
@@ -18,6 +18,8 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
|
|||||||
%\setcounter{tocdepth}{1} % А почему бы и нет?
|
%\setcounter{tocdepth}{1} % А почему бы и нет?
|
||||||
% Несколько сокращений
|
% Несколько сокращений
|
||||||
\newcommand{\sectiona}[1]{\section*{#1}\addcontentsline{toc}{section}{#1}}
|
\newcommand{\sectiona}[1]{\section*{#1}\addcontentsline{toc}{section}{#1}}
|
||||||
|
\newcommand{\subsectiona}[1]{\subsection*{#1}%
|
||||||
|
\addcontentsline{toc}{subsection}{#1}}
|
||||||
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
|
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
|
||||||
\newenvironment{caveat}[1][]{\smallskip\par\textbf{Предупреждение#1: }}%
|
\newenvironment{caveat}[1][]{\smallskip\par\textbf{Предупреждение#1: }}%
|
||||||
{\smallskip\par}
|
{\smallskip\par}
|
||||||
@@ -26,6 +28,8 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
|
|||||||
\newcommand{\qna}[1]{\medskip\par\textbf{Вопрос: #1}\nopagebreak\par Ответ:}
|
\newcommand{\qna}[1]{\medskip\par\textbf{Вопрос: #1}\nopagebreak\par Ответ:}
|
||||||
\newcommand\yousaywtf[1]{\emph{#1}}
|
\newcommand\yousaywtf[1]{\emph{#1}}
|
||||||
\newcommand\yousaywtfsk[1]{\yousaywtf{#1}\medskip\par}
|
\newcommand\yousaywtfsk[1]{\yousaywtf{#1}\medskip\par}
|
||||||
|
\newcommand\llquote{\texorpdfstring{<<}{"}}
|
||||||
|
\newcommand\rrquote{\texorpdfstring{>>}{"}}
|
||||||
% Настройка макета страницы
|
% Настройка макета страницы
|
||||||
\setlength{\hoffset}{-1.5cm}
|
\setlength{\hoffset}{-1.5cm}
|
||||||
\addtolength{\textwidth}{2cm}
|
\addtolength{\textwidth}{2cm}
|
||||||
@@ -2762,6 +2766,7 @@ PrivateNetwork=yes
|
|||||||
котором настраивается только интерфейс обратной петли.
|
котором настраивается только интерфейс обратной петли.
|
||||||
|
|
||||||
\subsection{Предоставление службам независимых каталогов \texttt{/tmp}}
|
\subsection{Предоставление службам независимых каталогов \texttt{/tmp}}
|
||||||
|
\label{sec:privatetmp}
|
||||||
|
|
||||||
Еще одна простая, но мощная опция настройки служб~--- +PrivateTmp=+:
|
Еще одна простая, но мощная опция настройки служб~--- +PrivateTmp=+:
|
||||||
\begin{Verbatim}
|
\begin{Verbatim}
|
||||||
@@ -5234,7 +5239,7 @@ RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|||||||
(network namespace), иерархию монтирования (mount namespace, также использовался
|
(network namespace), иерархию монтирования (mount namespace, также использовался
|
||||||
термин filesystem namespace), иерархию контрольных групп (cgroup namespace),
|
термин filesystem namespace), иерархию контрольных групп (cgroup namespace),
|
||||||
очереди сообщений POSIX и интерфейсы SysV IPC (IPC namespace), имя хоста (UTS
|
очереди сообщений POSIX и интерфейсы SysV IPC (IPC namespace), имя хоста (UTS
|
||||||
namespace), независимые списки индентификаторов процессов (PID namespace) и
|
namespace), независимые списки идентификаторов процессов (PID namespace) и
|
||||||
пользователей/групп (user namespace). Лежат в основе систем контейнерной
|
пользователей/групп (user namespace). Лежат в основе систем контейнерной
|
||||||
изоляции, таких как LXC и Docker. Также широко используются в systemd для
|
изоляции, таких как LXC и Docker. Также широко используются в systemd для
|
||||||
обеспечения безопасности~--- см. главы \ref{sec:chroots} и
|
обеспечения безопасности~--- см. главы \ref{sec:chroots} и
|
||||||
@@ -5262,6 +5267,684 @@ IPC)\footnote{Прим. перев.: Как и в предыдущем случ
|
|||||||
директивы в поставляемые по умолчанию юнит-файлы, так как эти люди лучше знают,
|
директивы в поставляемые по умолчанию юнит-файлы, так как эти люди лучше знают,
|
||||||
какие именно привилегии минимально необходимы для функционирования их демонов.
|
какие именно привилегии минимально необходимы для функционирования их демонов.
|
||||||
|
|
||||||
|
\sectiona{Динамические пользователи}
|
||||||
|
|
||||||
|
\emph{Коротко о главном: теперь вы можете настроить systemd таким образом, чтобы
|
||||||
|
он автоматически выделял новый идентификатор пользователя (UID) для службы при
|
||||||
|
ее запуске, и автоматически освобождал его при остановке службы. Такой подход
|
||||||
|
абсолютно безопасен и может также применяться в сочетании с другими технологями
|
||||||
|
systemd, в частности, одноразовыми службами (transient services), службами с
|
||||||
|
активацией через сокет и экземплярами служб.}
|
||||||
|
|
||||||
|
В выпуске
|
||||||
|
\href{https://lists.freedesktop.org/archives/systemd-devel/2017-October/039589.html}%
|
||||||
|
{systemd 235}, помимо прочих улучшений, значительно расширена поддержка
|
||||||
|
\emph{динамических пользователей} (базовая функциональность для которой
|
||||||
|
появилась еще в версии 232). Это мощная и удобная, но пока малоизвестная
|
||||||
|
технология, и в данной статье я попытаюсь исправить последний недостаток,
|
||||||
|
рассказав о ней более подробно.
|
||||||
|
|
||||||
|
Понятие \emph{пользователя} является одной из ключевых концепций безопасности
|
||||||
|
POSIX-совместимых операционных систем. Большинство созданных впоследствии
|
||||||
|
механизмов обеспечения безопасности (SELinux и другие системы мандатного
|
||||||
|
контроля доступа, capabilities, пространства имен пользователей и т.д.) так или
|
||||||
|
иначе связаны или взаимодействуют с концепцией пользователя. Даже если вы хотите
|
||||||
|
пересобрать ядро Linux, полностью отключив все возможные механизмы безопасности,
|
||||||
|
от пользователей вы, скорее всего, не~избавитесь.
|
||||||
|
|
||||||
|
Изначально, понятие пользователя было введено при создании многопользовательских
|
||||||
|
систем, рассчитанных на одновременную работу нескольких
|
||||||
|
пользователей-\emph{людей}, обеспечивая взаимную изоляцию и разделение ресурсов.
|
||||||
|
Однако, большинство современных UNIX-систем используют концепцию пользователей
|
||||||
|
иначе: несмотря на то, что реальный пользователь у них может быть только один
|
||||||
|
(или вообще ни одного!), в их списках пользователей (то есть файлах
|
||||||
|
+/etc/passwd+), записей намного больше. В наше время, большинство пользователей
|
||||||
|
типичной UNIX-системы являются \emph{системными}~--- они соответствуют
|
||||||
|
не~сидящим перед компьютером живым людям, а наборам полномочий (security
|
||||||
|
identity), с которыми запускаются системные службы (т.е. программы). Хотя
|
||||||
|
традиционные многопользовательские системы постепенно теряют свою актуальность,
|
||||||
|
лежащее в их основе понятие <<пользователь>> стало одним из краеугольных камней
|
||||||
|
в технологиях защиты UNIX-систем. Большинство служб в современной системе
|
||||||
|
работает от имени своего пользователем, которому даны минимально возможные
|
||||||
|
полномочия.
|
||||||
|
|
||||||
|
Создатели ОС Android хорошо понимали значимость концепции пользователя для
|
||||||
|
безопасности системы, и пошли еще дальше: в Android пользователи создаются
|
||||||
|
не~только для системных служб, но и для каждого графического приложения, что
|
||||||
|
позволяет обеспечить разделение ресурсов и защиту процессов разных приложений
|
||||||
|
друг от друга.
|
||||||
|
|
||||||
|
Тем не~менее, в традиционных Linux-системах концепции пользователей пока
|
||||||
|
уделяется меньше внимания. Несмотря на то, что она являтся ключевой технологией
|
||||||
|
обеспечения безопасности UNIX-системы, механизмы создания пользователей и
|
||||||
|
управления ими пока не~обладают достаточной гибкостью. В большинстве случаев,
|
||||||
|
если вы устанавливаете службу, которая выполняется от своего пользователя,
|
||||||
|
работу по созданию учетных записей берут на себя установочные скрипты RPM или
|
||||||
|
DEB-пакетов. После этого, созданный пользователь останется в системе уже
|
||||||
|
навсегда, даже если вы удалите соответствующий пакет. Большинство дистрибутивов
|
||||||
|
Linux используют для идентификаторов системных пользователей диапазон от 0 до
|
||||||
|
1000~--- не~так уж и много. Следовательно, создание пользователей является
|
||||||
|
<<дорогой>> операцией: количество идентификаторов ограничено, и не~существует
|
||||||
|
механизма для их автоматического освобождения после использования. Если вы
|
||||||
|
будете активно использовать концепцию системных пользователей, вы рано или
|
||||||
|
поздно исчерпаете доступный лимит.
|
||||||
|
|
||||||
|
У вас может возникнуть вопрос: почему системные пользователи не~удаляются при
|
||||||
|
удалении создавшего их пакета (как минимум, в большинстве дистрибутивов)?
|
||||||
|
Причиной этому является одно из важных свойств концепции пользователя (его можно
|
||||||
|
даже назвать \emph{ошибкой дизайна}): идентификаторы пользователей
|
||||||
|
сохраняются в атрибутах файлов (и некоторых других объектов, в частности,
|
||||||
|
элементов IPC). Если служба, работающая из-под отдельного системного
|
||||||
|
пользователя, создаст где-либо новый файл, то даже после остановки службы и
|
||||||
|
удаления ее пакета, числовой идентификатор ее пользователя (UID) останется в
|
||||||
|
метаданных этого файла. Если бы наша система удаляла системных пользователей
|
||||||
|
вместе с их пакетами, то рано или поздно этот идентификатор заняла бы
|
||||||
|
какая-нибудь другая служба. И это уже можно считать уязвимостью, так как файл с
|
||||||
|
данными одной службы становится доступен для другой. Как следствие, дистрибутивы
|
||||||
|
склонны избегать повторного использования UID, и каждый созданный системный
|
||||||
|
пользователь остается в системе навсегда.
|
||||||
|
|
||||||
|
Выше мы рассматривали сложившуюся к настоящему моменту ситуацию. А теперь
|
||||||
|
посмотрим, что нового вносит наша концепция динамических пользователей, и какие
|
||||||
|
проблемы она может решить.
|
||||||
|
|
||||||
|
\subsectiona{Что такое \llquote{}динамический пользователь\rrquote{}?}
|
||||||
|
|
||||||
|
Реализованный в systemd механизм динамических пользователей нацелен на упрощение
|
||||||
|
и удешевление операций создания пользователей <<на лету>>, и в перспективе
|
||||||
|
позволит значительно расширить область примнения концепции пользователей в
|
||||||
|
целом.
|
||||||
|
|
||||||
|
При создании или редактировании service-файла вашей службы, вы можете включить
|
||||||
|
для нее механизм динамических пользователей, добавив в секцию +[Service]+
|
||||||
|
директиву
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#DynamicUser=}%
|
||||||
|
{DynamicUser=yes}. После этого, при каждом запуске данной службы, для нее будет
|
||||||
|
на лету создаваться системный пользователь. При остановке службы он будет
|
||||||
|
автоматически удаляться. UID такого пользователя выбирается из диапазона
|
||||||
|
61184--65519 (при этом производится автоматическая проверка, исключающая
|
||||||
|
использование UID, занятых кем-либо еще).
|
||||||
|
|
||||||
|
Вы спросите, как же в таком случае решается вышеописанная проблема привязки
|
||||||
|
идентификаторов пользователей к файлам? Существуют как минимум два очевидных
|
||||||
|
подхода к ее решению:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Запретить службе создавать файлы, каталоги и объекты IPC.
|
||||||
|
\item Автоматически удалять созданные службой файлы, каталоги и объекты
|
||||||
|
IPC при ее остановке.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
systemd реализует одновременно обе стратегии, но применяет их к различным
|
||||||
|
областям рабочего окружения службы. А именно:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Установка +DynamicUser=yes+ также применяет директивы
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#ProtectSystem=}%
|
||||||
|
{ProtectSystem=strict} и
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#ProtectHome=}%
|
||||||
|
{ProtectHome=read-only}. В результате служба теряет возможность
|
||||||
|
что-либо писать практически во все каталоги системы, за
|
||||||
|
исключением специальных файловых систем (+/dev+, +/proc+ и
|
||||||
|
+/sys+) и временных каталогов (+/tmp+ и +/var/tmp+). (Кстати,
|
||||||
|
включать эти опции имеет смысл даже для служб, которые
|
||||||
|
не~используют режим +DynamicUser=yes+, так как это сильно
|
||||||
|
снижает возможный ущерб при взломе службы.)
|
||||||
|
\item Установка +DynamicUser=yes+ автоматически применяет директиву
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#PrivateTmp=}%
|
||||||
|
{PrivateTmp=yes}. В результате для этой службы создаются свои
|
||||||
|
собственные, изолированные от других служб экземпляры каталогов
|
||||||
|
+/tmp+ и +/var/tmp+\footnote{Прим. перев.: Технически это
|
||||||
|
реализовано следующим образом: в системных +/tmp+ и +/var/tmp+
|
||||||
|
создаются подкаталоги со специальными именами (построенными на
|
||||||
|
основе имени службы и (псевдо)случайных последовательностей
|
||||||
|
символов), принадлежащие руту и имеющие права доступа 0700 (это
|
||||||
|
граничные каталоги~--- принцип их работы описан в данной статье
|
||||||
|
ниже), а внутри них создаются подкаталоги +tmp+ с правами 0777.
|
||||||
|
Для самой службы создается пространство имен монтирования (mount
|
||||||
|
namespace), в котором эти подкаталоги bind-монтируются в +/tmp+
|
||||||
|
и +/var/tmp+ соответственно. См. также раздел
|
||||||
|
\ref{sec:privatetmp}.}, причем их жизненный цикл привязан к
|
||||||
|
жизненному циклу службы: при остановке службы удаляется
|
||||||
|
не~только ее пользователь, но и ее временные каталоги. (Опять же
|
||||||
|
замечу, что эту директиву имеет смысл применять и без
|
||||||
|
+DynamicUser=yes+, так как она тоже повышает безопасность вашей
|
||||||
|
системы.)
|
||||||
|
\item Установка +DynamicUser=yes+ автоматически применяет директиву
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#RemoveIPC=}%
|
||||||
|
{RemoveIPC=yes}, которая обеспечивает автоматическое удаление
|
||||||
|
объектов межпроцессного взаимодействия (IPC) SysV и POSIX (общая
|
||||||
|
память, очереди сообщений, семафоры), принадлежащих службе, при
|
||||||
|
ее остановке. Как следствие, жизненный цикл IPC-объектов также
|
||||||
|
привязан к жизненному циклу службы и ее пользователя. (И снова:
|
||||||
|
эту директиву имеет смысл применять и для обычных служб!)
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Использование этих четырех опций позволяет практически полностью изолировать
|
||||||
|
службу с динамическим пользователем от основной системы. Она не~может создавать
|
||||||
|
файлы или каталоги где-либо, кроме +/tmp+ и +/var/tmp+, где они будут удалены
|
||||||
|
при ее остановке, как и созданные ею объекты IPC. Таким образом, проблема
|
||||||
|
владения файлами, каталогами и объектами IPC, успешно решена.
|
||||||
|
|
||||||
|
Если вам нужно немного приоткрыть <<железный занавес>> и дать службе возможность
|
||||||
|
взаимодействовать с другими программами, это можно сделать при помощи параметра
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#RuntimeDirectory=}%
|
||||||
|
{RuntimeDirectory=}. Подкаталог с указанным в этом параметре именем создается в
|
||||||
|
каталоге +/run+ при запуске службы, принадлежит ее пользователю, и тоже
|
||||||
|
автоматически удаляется при ее остановке. Однако, при этом он открыт для доступа
|
||||||
|
других программ, так что служба может размещать в нем различные интерфейсные
|
||||||
|
объекты (например, UNIX-сокеты), жизненный цикл которых также будет привязан к
|
||||||
|
жизненному циклу службы. Например, если вы зададите для своей службы
|
||||||
|
+RuntimeDirectory=foobar+, то увидите, что при ее запуске создается каталог
|
||||||
|
+/run/foobar+, а при ее остановке он удаляется. (Как и другие описанные здесь
|
||||||
|
директивы, +RuntimeDirectory=+ прекрасно может работать и без +DynamicUser=+,
|
||||||
|
предоставляя для вашей службы автоматически создаваемый и удаляемый каталог с
|
||||||
|
правильным владельцем.)
|
||||||
|
|
||||||
|
\subsectiona{Долговременное хранение данных}
|
||||||
|
|
||||||
|
Вышеописанный способ изоляции службы, хотя и может оказаться полезен в некоторых
|
||||||
|
случаях, имеет одно существенное ограничение: служба не~может сохранить
|
||||||
|
какие-либо данные так, чтобы получить к ним доступ при последующих запусках.
|
||||||
|
Почти все системное дерево каталогов доступно ей только для чтения, а все
|
||||||
|
доступные на запись каталоги удаляются при остановке и перезапуске.
|
||||||
|
|
||||||
|
В выпуске systemd 235 это ограничение было снято: мы добавили три новых
|
||||||
|
опции~---
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#RuntimeDirectory=}%
|
||||||
|
{StateDirectory=}, +LogsDirectory=+ и +CacheDirectory=+. По большей части они
|
||||||
|
действуют аналогично вышеописанной опции +RuntimeDirectory=+, но создают
|
||||||
|
подкаталоги не~в +/run+, а в +/var/lib+, +/var/log+ и +/var/cache+
|
||||||
|
соответственно. Но самое главное их отличие состоит в том, что эти подкаталоги
|
||||||
|
\emph{не~удаляются} при остановке службы, что позволяет использовать их для
|
||||||
|
долговременного хранения данных.
|
||||||
|
|
||||||
|
Очевидный вопрос: как при этом решается вышеописанная проблема с динамическими
|
||||||
|
идентификаторами пользователей?
|
||||||
|
|
||||||
|
Для решения этой задачи мы обратились к опыту систем контейнерной изоляции.
|
||||||
|
При работе с контейнерами возникает схожая проблема: контейнеры и хост
|
||||||
|
используют частично или полностью перекрывающиеся наборы числовых идентификаторов
|
||||||
|
пользователей, а значит, пользователи хоста могут получить доступ к
|
||||||
|
файлам контейнера, которые принадлежат пользователям с таким же UID~--- а ведь
|
||||||
|
это может быть совсем другой пользователь, никак не~связанный со своим хостовым
|
||||||
|
<<двойником>> (кроме случаев, когда используются пространства имен
|
||||||
|
пользователей\footnote{Прим. перев.: В таких случаях используется механизм
|
||||||
|
отображения UID (user-remap), когда пользователям, работающим с user
|
||||||
|
namespaces (например, +dockremap+ в Docker), выдаются диапазоны UID хоста (см.
|
||||||
|
\hreftt{http://man7.org/linux/man-pages/man5/subuid.5.html}{/etc/subuid}), на
|
||||||
|
которые отображаются UID гостевой системы. Это решает проблему пересечения UID
|
||||||
|
хоста и гостя. Без присвоения такого диапазона гость будет иметь только один
|
||||||
|
UID (в пространстве гостя он может быть любым, даже нулевым), который для хоста
|
||||||
|
(и его файловой системы) будет виден как UID пользователя контейнера.}).
|
||||||
|
Особенно неприятно, если это происходит с исполняемым файлом, имеющим
|
||||||
|
+suid+-бит~--- тогда речь идет уже не~просто о доступе к чужим данным, а о
|
||||||
|
потенциальной возможности повышения привилегий. Чтобы предотвратить подобные
|
||||||
|
ситуации, системы управления контейнерами обычно помещают корневые системы
|
||||||
|
гостей в специальный \emph{граничный} каталог, имеющий ограниченные права
|
||||||
|
доступа (обычно: права 0700, владелец +root:root+). При этом,
|
||||||
|
непривилигерованные пользователи хоста уже не~могут добраться до файлов,
|
||||||
|
принадлежащих их контейнерным <<двойникам>>, просто потому, что не~имеют доступа
|
||||||
|
ко всему, что лежит в граничном каталоге. В UNIX, чтобы получить доступ к файлу,
|
||||||
|
вы должны иметь доступ ко всем каталогам по пути к нему, начиная с корневого.
|
||||||
|
|
||||||
|
Как это работает для наших служб с динамическими пользователями? Предположим,
|
||||||
|
что вы указали +StateDirectory=foobar+, но \emph{не~включали} режим
|
||||||
|
+DynamicUser=+. В момент запуска такой службы, для нее будет создан каталог
|
||||||
|
+/var/lib/foobar+, принадлежащий пользователю, от которого запускается
|
||||||
|
служба\footnote{Прим. перев.: Если режим +DynamicUser=+ отключен, пользователь
|
||||||
|
службы определяется директивой
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#User=}%
|
||||||
|
{User=}. Более подробно ее роль при включенном и выключенном режиме
|
||||||
|
динамических пользователей рассмотрена \hyperref[itm:setuser]{ниже}.}. Этот
|
||||||
|
каталог и его содержимое \emph{не~удаляются} после завершения службы. Если же мы
|
||||||
|
включим для нашей службы режим +DynamicUser=+, алгоритм станет немного
|
||||||
|
сложнее~--- теперь +/var/lib/foobar+ уже не~каталог, а принадлежащая руту
|
||||||
|
символьная ссылка на каталог +/var/lib/private/foobar+, который принадлежит
|
||||||
|
динамическому пользователю, выделенному для службы. Каталог +/var/lib/private+
|
||||||
|
играет роль граничного: он принадлежит +root:root+, и имеет права 0700. При
|
||||||
|
остановке службы, и символьная ссылка, и каталог, на который она указывает,
|
||||||
|
не~удаляются. Каталог продолжает принадлежать теперь уже освобожденному
|
||||||
|
идентификатору пользователя, однако граничный каталог не~позволит получить к
|
||||||
|
нему доступ ни пользователям хоста, ни другим службам, получившим тот же UID.
|
||||||
|
|
||||||
|
Следующий вопрос: если граничный каталог столь успешно защищает подкаталог с
|
||||||
|
данными службы, то как сама служба сможет получить к ним доступ? Для этого,
|
||||||
|
служба запускается в специально модифицированном пространстве имен точек
|
||||||
|
монтирования (mount namespace): помимо уже упомянутых хитростей с монтированием
|
||||||
|
+/tmp+ и +/var/tmp+\footnote{Прим. перев.: Строго говоря, <<хитростей>> там
|
||||||
|
гораздо больше~--- упомянутые выше директивы +ProtectSystem=strict+ и
|
||||||
|
+ProtectHome=read-only+ предполагают перемонтирование целого ряда каталогов,
|
||||||
|
включая корневой. Но к теме это действительно не~относится.}, добавляется
|
||||||
|
+tmpfs+, смонтированная в +/var/lib/private+ и доступная только на чтение, с
|
||||||
|
правами, разрешающими чтение из этого каталога (0755). Внутри этой файловой
|
||||||
|
системы создан каталог +foobar+, в который bind-монтируется каталог
|
||||||
|
+/var/lib/private/foobar+ с хоста. В результате и для хоста, и для службы
|
||||||
|
содержимое этого каталога находится по одному и тому же пути, но при этом <<с
|
||||||
|
точки зрения>> службы каталог +/var/lib/private+ уже не~является
|
||||||
|
ограничительным, и в нем отсутствуют подкаталоги, принадлежащие другим службам,
|
||||||
|
что обеспечивает полную изоляцию служб друг от друга. Символьная сслыка
|
||||||
|
+/var/lib/foobar+ позволяет не~задумываться о том, используется граничный
|
||||||
|
каталог или нет: и при включенном, и при выключенном режиме динамических
|
||||||
|
пользователей, каталог с данными программы доступен по указанному пути.
|
||||||
|
|
||||||
|
Назревает очередной вопрос. Предположим, что мы запустили службу от динамического
|
||||||
|
пользователя и с настроенным каталогом для хранения данных. Она получила
|
||||||
|
некоторый UID (назовем его $X$), которому принадлежит этот каталог. Потом мы
|
||||||
|
перезапустили службу, и она получила новый UID $Y\neq X$. Что тогда произойдет?
|
||||||
|
Неужели каталог и его содержимое будут все еще принадлжать UID $X$, и наша
|
||||||
|
служба уже не~сможет получить к ним доступ? Конечно же, нет~--- systemd
|
||||||
|
рекурсивно поменяет владельца для каталога и его содержимого.
|
||||||
|
|
||||||
|
Разумеется, операция рекурсивной смены владельца (+chown()+) для дерева
|
||||||
|
каталогов может оказаться весьма затратной (хотя, по моему личному опыту, для
|
||||||
|
большинства служб это не~так критично, как кажется на первый взгляд), и поэтому
|
||||||
|
мы ввели две оптимизации, сводящие к минимуму вероятность такой операции.
|
||||||
|
Во-первых, systemd начинает подбор подходящего UID с некоторого значения,
|
||||||
|
полученного путем хеширования имени службы. Таким образом, если имя службы
|
||||||
|
не~поменялось, то при следующем запуске она, скорее всего, получит тот же UID. В
|
||||||
|
результате, необходимость в +chown()+ отпадает (разумеется, после
|
||||||
|
соответствующих проверок). Во-вторых, если указанный каталог уже существует, и
|
||||||
|
его владельцем является неиспользуемый UID из динамического диапазона, то службе
|
||||||
|
присваивается именно этот UID, что также увеличивает шансы избежать +chown()+.
|
||||||
|
(На самом деле, выделенный сейчас диапазон на четыре с лишним тысячи UID не~так
|
||||||
|
уж и велик, и при активном применении динамических пользователей рано или поздно
|
||||||
|
появятся ситуации, когда обойтись без +chown()+ уже не~удастся.)
|
||||||
|
|
||||||
|
Директивы +CacheDirectory=+ и +LogsDirectory=+ работают по аналогии со
|
||||||
|
+StateDirectory=+. Единственное их отличие состоит в том, что они управляют
|
||||||
|
подкаталогами в +/var/cache+ и +/var/log+, и используют граничные каталоги
|
||||||
|
+/var/cache/private+ и +/var/log/private+ соответственно.
|
||||||
|
|
||||||
|
\subsectiona{Примеры}
|
||||||
|
|
||||||
|
Итак, мы ознакомились с теорией. Попробуем теперь посмотреть, как все это
|
||||||
|
работает на практике. Простой пример:
|
||||||
|
\begin{Verbatim}
|
||||||
|
# cat > /etc/systemd/system/dynamic-user-test.service <<EOF
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/sleep 4711
|
||||||
|
DynamicUser=yes
|
||||||
|
EOF
|
||||||
|
# systemctl daemon-reload
|
||||||
|
# systemctl start dynamic-user-test
|
||||||
|
# systemctl status dynamic-user-test
|
||||||
|
dynamic-user-test.service
|
||||||
|
Loaded: loaded (/etc/systemd/system/dynamic-user-test.service; static; vendor preset: disabled)
|
||||||
|
Active: active (running) since Fri 2017-10-06 13:12:25 CEST; 3s ago
|
||||||
|
Main PID: 2967 (sleep)
|
||||||
|
Tasks: 1 (limit: 4915)
|
||||||
|
CGroup: /system.slice/dynamic-user-test.service
|
||||||
|
└─2967 /usr/bin/sleep 4711
|
||||||
|
|
||||||
|
Okt 06 13:12:25 sigma systemd[1]: Started dynamic-user-test.service.
|
||||||
|
# ps -e -o pid,comm,user | grep 2967
|
||||||
|
2967 sleep dynamic-user-test
|
||||||
|
# id dynamic-user-test
|
||||||
|
uid=64642(dynamic-user-test) gid=64642(dynamic-user-test) groups=64642(dynamic-user-test)
|
||||||
|
# systemctl stop dynamic-user-test
|
||||||
|
# id dynamic-user-test
|
||||||
|
id: ‘dynamic-user-test’: no such user
|
||||||
|
\end{Verbatim}
|
||||||
|
|
||||||
|
Мы создали юнит-файл службы с включенным режимом +DynamicUser=+, запустили эту
|
||||||
|
службу, убедились, что она работает нормально, запросили данные о пользователе,
|
||||||
|
от которого она запущена (в нашем случае его имя совпадает с именем службы~---
|
||||||
|
systemd использует его автоматически, если оно соответствует синтаксису имени
|
||||||
|
пользователя, и вы не~указали явно другого имени), остановили службу и
|
||||||
|
убедились, что такого пользователя больше не~существует.
|
||||||
|
|
||||||
|
Уже неплохо, правда? Следующий шаг~--- повторим то же самое с интерактивной
|
||||||
|
\emph{одноразовой} службой. Для тех, кто не~очень хорошо разбирается в тонкостях
|
||||||
|
systemd: одноразовая служба (transient service) создается и запускается <<на
|
||||||
|
лету>>, без каких-либо конфигурационных файлов~--- например, с помощью программы
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd-run.html}%
|
||||||
|
{systemd-run}, которую можно запустить непосредственно из командной оболочки.
|
||||||
|
Короче: запуск службы без предварительного создания юнит-файла.
|
||||||
|
\begin{Verbatim}
|
||||||
|
# systemd-run --pty --property=DynamicUser=yes --property=StateDirectory=wuff /bin/sh
|
||||||
|
Running as unit: run-u15750.service
|
||||||
|
Press ^] three times within 1s to disconnect TTY.
|
||||||
|
sh-4.4$ id
|
||||||
|
uid=63122(run-u15750) gid=63122(run-u15750) groups=63122(run-u15750) context=system_u:system_r:initrc_t:s0
|
||||||
|
sh-4.4$ ls -al /var/lib/private/
|
||||||
|
total 0
|
||||||
|
drwxr-xr-x. 3 root root 60 6. Okt 13:21 .
|
||||||
|
drwxr-xr-x. 1 root root 852 6. Okt 13:21 ..
|
||||||
|
drwxr-xr-x. 1 run-u15750 run-u15750 8 6. Okt 13:22 wuff
|
||||||
|
sh-4.4$ ls -ld /var/lib/wuff
|
||||||
|
lrwxrwxrwx. 1 root root 12 6. Okt 13:21 /var/lib/wuff -> private/wuff
|
||||||
|
sh-4.4$ ls -ld /var/lib/wuff/
|
||||||
|
drwxr-xr-x. 1 run-u15750 run-u15750 0 6. Okt 13:21 /var/lib/wuff/
|
||||||
|
sh-4.4$ echo hello > /var/lib/wuff/test
|
||||||
|
sh-4.4$ exit
|
||||||
|
exit
|
||||||
|
# id run-u15750
|
||||||
|
id: ‘run-u15750’: no such user
|
||||||
|
# ls -al /var/lib/private
|
||||||
|
total 0
|
||||||
|
drwx------. 1 root root 66 6. Okt 13:21 .
|
||||||
|
drwxr-xr-x. 1 root root 852 6. Okt 13:21 ..
|
||||||
|
drwxr-xr-x. 1 63122 63122 8 6. Okt 13:22 wuff
|
||||||
|
# ls -ld /var/lib/wuff
|
||||||
|
lrwxrwxrwx. 1 root root 12 6. Okt 13:21 /var/lib/wuff -> private/wuff
|
||||||
|
# ls -ld /var/lib/wuff/
|
||||||
|
drwxr-xr-x. 1 63122 63122 8 6. Okt 13:22 /var/lib/wuff/
|
||||||
|
# cat /var/lib/wuff/test
|
||||||
|
hello
|
||||||
|
\end{Verbatim}
|
||||||
|
|
||||||
|
В приведенном примере, мы запускаем интерактивную оболочку +/bin/sh+ как
|
||||||
|
одноразовую службу +run-u15750.service+ (+systemd-run+ выбрал это имя
|
||||||
|
автоматически, так как мы не~указали имя службы явно\footnote{Прим. перев.: Это
|
||||||
|
можно было бы сделать параметром +systemd-run+ +--unit=+.}) под динамическим
|
||||||
|
пользователем, имя которого, как и в предыдущем примере, унаследовано от имени
|
||||||
|
службы. Так как мы задали +StateDirectory=wuff+, то каталог для долговременного
|
||||||
|
хранения данных нашей службы должен быть доступен под именем +/var/lib/wuff+. В
|
||||||
|
интерактивной оболочке, запущенной в рамках службы, команда +ls+ показывает
|
||||||
|
граничный каталог +/var/lib/private+ и его содержимое, а также символьную ссылку
|
||||||
|
+/var/lib/wuff+, указывающую на его подкаталог +wuff+. Наконец, перед
|
||||||
|
завершением оболочки, мы создаем там тестовый файл. Вернувшись в нашу исходную
|
||||||
|
оболочку, мы проверяем, существует ли еще пользователь, выделенный для нашей
|
||||||
|
службы~--- нет, он автоматически удален в момент завершения службы (оболочки).
|
||||||
|
При помощи аналогичных команд +ls+ мы снова проверяем каталог долговременного
|
||||||
|
хранения данных службы, на этот раз с хоста. Видим мы почти то же самое, с
|
||||||
|
двумя исключениями: во-первых, пользователь и группа, владеющие каталогом и его
|
||||||
|
содержимым, отображаются уже в виде числовых идентификатов, а не~имен. Это
|
||||||
|
обусловлено тем, что пользователь (то есть ассоциация числового идентификатора с
|
||||||
|
некоторым именем) был удален в момент завершения службы. Во-вторых, отличаются
|
||||||
|
права доступа к граничному каталогу: 0755 (читать могут все) изнутри службы, и
|
||||||
|
0700 (читать может только владелец, т.е. рут)~--- с хоста.
|
||||||
|
|
||||||
|
А теперь попробуем запустить еще одну одноразовую службу, указав ей тот же
|
||||||
|
каталог с данными:
|
||||||
|
\begin{Verbatim}
|
||||||
|
# systemd-run --pty --property=DynamicUser=yes --property=StateDirectory=wuff /bin/sh
|
||||||
|
Running as unit: run-u16087.service
|
||||||
|
Press ^] three times within 1s to disconnect TTY.
|
||||||
|
sh-4.4$ cat /var/lib/wuff/test
|
||||||
|
hello
|
||||||
|
sh-4.4$ ls -al /var/lib/wuff/
|
||||||
|
total 4
|
||||||
|
drwxr-xr-x. 1 run-u16087 run-u16087 8 6. Okt 13:22 .
|
||||||
|
drwxr-xr-x. 3 root root 60 6. Okt 15:42 ..
|
||||||
|
-rw-r--r--. 1 run-u16087 run-u16087 6 6. Okt 13:22 test
|
||||||
|
sh-4.4$ id
|
||||||
|
uid=63122(run-u16087) gid=63122(run-u16087) groups=63122(run-u16087) context=system_u:system_r:initrc_t:s0
|
||||||
|
sh-4.4$ exit
|
||||||
|
exit
|
||||||
|
\end{Verbatim}
|
||||||
|
|
||||||
|
Как видим, +systemd-run+ сгенерировал для этой службы уже другое имя, которое
|
||||||
|
перешло и к ее пользователю, однако числовой идентификатор пользователя остался
|
||||||
|
прежним~--- systemd подхватил UID владельца каталога с данными (предварительно
|
||||||
|
убедившись, что он больше никем не~используется). Этим иллюстрируется
|
||||||
|
вышеописанная оптимизация алгоритма выбора UID (цикл выбора идентификатора
|
||||||
|
начинается с UID владельца существующего каталога с данными): рекурсивного
|
||||||
|
выполнения +chown()+ удалось избежать.
|
||||||
|
|
||||||
|
Надеюсь, вышеприведенные примеры помогли вам разобраться и в самой идее, и в
|
||||||
|
особенностях ее реализации.
|
||||||
|
|
||||||
|
\subsectiona{Практическое применение}
|
||||||
|
|
||||||
|
Итак, мы рассмотрели, как включить механизм динамических пользователей для
|
||||||
|
юнита, и разобрались, как он реализован. Самое время попытаться понять, где и
|
||||||
|
для чего он может применяться.
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Одно из главных достоинств технологии динамического выделения
|
||||||
|
UID~--- возможность запускать службы с урезаннмыми привилегиями
|
||||||
|
(то есть, от отдельного пользователя), не~оставляя в системе
|
||||||
|
никаких артефактов. Системный пользователь создается и
|
||||||
|
используется, но после применения автоматически удаляется, и
|
||||||
|
повторное применение его UID не~несет никаких рисков для
|
||||||
|
безопасности. Мы можем одной командой запускать одноразовые
|
||||||
|
службы для выполнения каких-либо операций, изолируя их под
|
||||||
|
отдельным идентификатором пользователя, без необходимости
|
||||||
|
вручную создавать и удалять учетную запись, и не~расходуя
|
||||||
|
доступные UID попусту.
|
||||||
|
\item Во многих случаях, запуск службы уже не~требует предварительной
|
||||||
|
подготовки со стороны пакетного менджера. Другими словами,
|
||||||
|
большинство операций +useradd+/+mkdir+/+chown+/+chmod+,
|
||||||
|
выполняемых пост-инсталляционными скриптами пакетов, а также
|
||||||
|
дополнительные конфигурационные файлы в
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/sysusers.d.html}%
|
||||||
|
{sysusers.d} и
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html}%
|
||||||
|
{tmpfiles.d} становятся необязательными, так как эти операции
|
||||||
|
выполняются автоматически благодаря директивам +DynamicUser=+ и
|
||||||
|
+StateDirectory=+/+CacheDirectory=+/+LogsDirectory=+, причем
|
||||||
|
не~при установке/удалении пакета, а непосредственно при
|
||||||
|
запуске/остановке службы.
|
||||||
|
\item Сочетание технологий динамических пользователей и одноразовых
|
||||||
|
служб предоставляет простой механизм изоляции приложений.
|
||||||
|
Например, предположим, что мы не~доверяем бинарнику +sort+.
|
||||||
|
Мы можем поместить его в простую и надежную песочницу
|
||||||
|
динамического пользователя при помощи +systemd-run+, и при этом
|
||||||
|
сохранить возможность подключать ее через каналы (pipelines) к
|
||||||
|
другим программам. Простенький пример конвейера, второй элемент
|
||||||
|
которого запущен от динамического пользователя (который
|
||||||
|
уничтожается после завершения конвейера):
|
||||||
|
\begin{Verbatim}
|
||||||
|
# cat some-file.txt | systemd-run --pipe --property=DynamicUser=1 sort -u | \
|
||||||
|
grep -i foobar > some-other-file.txt
|
||||||
|
\end{Verbatim}
|
||||||
|
\item Сочетая технологию динамических пользователей и экземпляров
|
||||||
|
служб\footnote{Прим перев.: Более подробно работа с экземплярами
|
||||||
|
служб рассмотрена в главе~\ref{sec:instances}.}, можно получить
|
||||||
|
гибкой и полностью автоматический механизм управления
|
||||||
|
идентификаторами пользователей. Допустим, мы создаем шаблон
|
||||||
|
службы +/etc/systemd/system/foobard@.service+:
|
||||||
|
\begin{Verbatim}
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/myfoobarserviced
|
||||||
|
DynamicUser=1
|
||||||
|
StateDirectory=foobar/%i
|
||||||
|
\end{Verbatim}
|
||||||
|
Теперь предположим, что вы запускаете экземпляр этой службы
|
||||||
|
для одного из своих клиентов:
|
||||||
|
\begin{Verbatim}
|
||||||
|
# systemctl enable foobard@customerxyz.service --now
|
||||||
|
\end{Verbatim}
|
||||||
|
Готово! (Надеюсь, понятно, что эту операцию можно повторять
|
||||||
|
многократно, подставляя каждый раз вместо +customerxyz+
|
||||||
|
идентификаторы различных клиентов.)
|
||||||
|
\item Сочетая технологии динамических пользователей и сокет-активации,
|
||||||
|
вы легко можете получить систему, где каждое входящее соединение
|
||||||
|
обслуживается экземпляром процесса, работающим в песочнице
|
||||||
|
динамически выделенного UID\footnote{Прим перев.: Здесь идет
|
||||||
|
речь о сокет-активации <<в стиле inetd>>, когда на каждое
|
||||||
|
соединение создается экземпляр службы. Более подробно она
|
||||||
|
обсуждается в главе~\ref{sec:inetd}.}. Пример конфигурации
|
||||||
|
сокета +waldo.socket+:
|
||||||
|
\begin{Verbatim}
|
||||||
|
[Socket]
|
||||||
|
ListenStream=2048
|
||||||
|
Accept=yes
|
||||||
|
\end{Verbatim}
|
||||||
|
И соответствующего ему шаблона службы +waldo@.service+:
|
||||||
|
\begin{Verbatim}
|
||||||
|
[Service]
|
||||||
|
ExecStart=-/usr/bin/myservicebinary
|
||||||
|
DynamicUser=yes
|
||||||
|
\end{Verbatim}
|
||||||
|
В результате, systemd будет слушать TCP-порт 2048, и на каждое
|
||||||
|
входящее соединение создавать новый экземпляр +waldo@.service+,
|
||||||
|
каждый раз с новым идентификатором пользователя, обеспечивающим
|
||||||
|
его изоляцию от остальных экземпляров.
|
||||||
|
\item Динамическое выделение пользователей хорошо сочетается с
|
||||||
|
<<системами без состояния>> (state-less systems), то есть
|
||||||
|
системами, которые запускаются с пустыми каталогами +/etc+ и
|
||||||
|
+/var+. Динамическим выделение UID и директивы
|
||||||
|
+StateDirectory=+, +CacheDirectory=+, +LogsDirectory=+ и
|
||||||
|
+RuntimeDirectory=+ позволяет автоматических создавать
|
||||||
|
пользователя и необходимые службе каталоги непосредственно перед
|
||||||
|
ее запуском.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Динамическое выделение пользователей~--- масштабная и глобальная концепция, и ее
|
||||||
|
применение, разумеется, не~ограничивается приведенным списком. Этот список~---
|
||||||
|
всего лишь попытка разбудить ваше воображение, дать начальный импульс к
|
||||||
|
размышлениям.
|
||||||
|
|
||||||
|
\subsectiona{Рекомендации сопровождающим пакетов}
|
||||||
|
|
||||||
|
Я уверен, что для значительной доли служб, поставляемых в современных
|
||||||
|
дистрибутивах, опции +DynamicUser=+, +StateDirectory=+ и т.д., могут оказаться
|
||||||
|
весьма полезны. Во многих случаях они позволят вообще отказаться от +post-inst+
|
||||||
|
скриптов, а также конфигурационных файлов в +sysusers.d+ и +tmpfiles.d+,
|
||||||
|
объединив все необходимые настройки непосредственно в юнит-файле. Так что, если
|
||||||
|
вы сопровождаете какой-либо пакет со службой, пожалуйста, рассмотрите
|
||||||
|
возможность использования этих директив. Тем не~менее, существует ряд ситуаций,
|
||||||
|
когда данные директивы неэффективны или неприменимы:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Службы, которым нужно писать куда-либо за пределами разрешенного
|
||||||
|
списка каталогов (+/run/<package>+, +/var/lib/<package>+,
|
||||||
|
+/var/cache/<package>+, +/var/log/<package>+, +/var/tmp+, +/tmp+,
|
||||||
|
+/dev/shm+) не~совместимы с описанным подходом. Например, демон,
|
||||||
|
обновляющий систему~--- ему, как минимум, необходим доступ на
|
||||||
|
запись в +/usr+.
|
||||||
|
\item Службы, которые управляют набором процессов, запущенных от
|
||||||
|
различных пользователей, например, некоторые SMTP-серверы. Если
|
||||||
|
ваша служба построена по принципу \emph{суперсервера}, то
|
||||||
|
управление идентификаторами пользователей для своих процессов
|
||||||
|
она должна осуществлять сама~--- systemd не~должен в это
|
||||||
|
вмешиваться.
|
||||||
|
\item Службы, запускаемые от рута, и вообще требующие расширенных
|
||||||
|
привилегий.
|
||||||
|
\item Службы, котороые должны запускаться в пространстве имен
|
||||||
|
монтирования хоста (например, если служба должна создавать точки
|
||||||
|
монтирования, видимые для всей системы). Как уже упоминалось
|
||||||
|
выше, +DynamicUser=+ задействует механизмы +ProtectSystem=+,
|
||||||
|
+PrivateTmp=+ и т.д., которые основаны на запуске службы в
|
||||||
|
отдельном пространстве имен монтирования.
|
||||||
|
\item В вашем дистрибутиве пока нет свежих версий systemd: 232
|
||||||
|
(поддержка +DynamicUser=+) или 235 (поддержка +StateDirectory=+
|
||||||
|
и аналогичных ей опций).
|
||||||
|
\item Правила создания пакетов для вашего дистрибутива не~разрешают
|
||||||
|
подобный подход. Уточните эти моменты в правилах и, при
|
||||||
|
необходимости, обсудите данный вопрос в рассылке вашего
|
||||||
|
дистрибутива.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsectiona{Дополнительные замечания}
|
||||||
|
|
||||||
|
Еще несколько замечаний, непосредственно относящихся к обсуждаемой теме:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Обратите внимание, что процесс выделения и удаления динамических
|
||||||
|
пользователей никак не~затрагивает +/etc/passwd+. Добавление
|
||||||
|
пользователя в базу данных оусществляется при помощи NSS-модуля
|
||||||
|
glibc
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/nss-systemd.html}%
|
||||||
|
{nss-systemd}\footnote{Прим. перев.: Разумеется, чтобы
|
||||||
|
преобразование <<имя-идентификатор>> для пользователя и его
|
||||||
|
группы работало корректно, это модуль должен быть указан в
|
||||||
|
строках +passwd:+ и +group:+ файла +/etc/nsswitch.conf+. Примеры
|
||||||
|
приведены на странице руководства модуля.}, и эта информация
|
||||||
|
никогда не~попадает на диск.
|
||||||
|
\item В традиционных UNIX-системах, демоны сбрасывают привилегии с рута
|
||||||
|
до обычного пользователя самостоятельно, в то время как механизм
|
||||||
|
динамических пользователей предполагает, что этим должен
|
||||||
|
заниматься systemd. В версии systemd 235 добавлена возможность
|
||||||
|
совместить механизм динамических пользователей с самостоятельным
|
||||||
|
сбросом привилегий процессом службы. Для этого, включите опцию
|
||||||
|
+DynamicUser=+, а в опции
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.exec.html\#User=}%
|
||||||
|
{User=} укажите имя пользователя, в которого ваша служба
|
||||||
|
перевоплотится (+setuid()+) после инициализации. В результате, в
|
||||||
|
момент запуска службы systemd создаст динамического пользователя
|
||||||
|
с указанным именем. Далее, в директиве
|
||||||
|
\hreftt{https://www.freedesktop.org/software/systemd/man/systemd.service.html\#ExecStart=}%
|
||||||
|
{ExecStart=} непосредственно перед командой запуска укажите
|
||||||
|
символ <<+!+>>. После этого, пользователь для службы будет
|
||||||
|
создаваться, но запускаться она будет от рута~--- systemd
|
||||||
|
будет считать, что служба сама сбросит полномочия в ходе
|
||||||
|
инициализации. Например: +ExecStart=!/usr/bin/mydaemond+. При
|
||||||
|
этом, регистрация соответствия имени и идентификатора
|
||||||
|
пользователя в базе данных производится, как и прежде, при
|
||||||
|
запуске службы, и поэтому процесс демона сможет без проблем
|
||||||
|
преобразововать имя пользователя в UID.
|
||||||
|
\item У вас может возникнуть вопрос: почему для динамического выделения
|
||||||
|
UID выбран именно диапазон 61184--65519 (в шестнадцатеричной
|
||||||
|
записи 0xEF00--0xFFEF)? Он был выбран потому, что большинство
|
||||||
|
дистрибутивов (например, Fedora) используют для обычных
|
||||||
|
пользователей идентификаторы ниже 60000, и мы не~хотим
|
||||||
|
переступать эту границу. Также мы делаем небольшой отступ от
|
||||||
|
65535, так как некоторые UID вблизи этого значения имеют
|
||||||
|
специальное значение (65535 часто трактуется как
|
||||||
|
<<некорректный>> или <<отсутствующий>> UID, так как является
|
||||||
|
представлением числа $-1$ в 16-битном целом типе; 65534 обычно
|
||||||
|
соответствует пользователю +nobody+, и некоторые подсистемы ядра
|
||||||
|
отображают в это значение <<посторонние>>
|
||||||
|
идентификаторы\footnote{Прим. перев.: Например, изнутри
|
||||||
|
пространства имен пользователей, все пользователи хоста, кроме
|
||||||
|
создателя пространства, выглядят как +nobody+.}). И наконец, мы
|
||||||
|
не~хотим выходить за пределы 16-битного целого типа. Даже с
|
||||||
|
распространением технологии пространств имен пользователей,
|
||||||
|
контейнерам все равно не~нужен весь диапазон значений,
|
||||||
|
предоставляемый 32-битным целым типом, который используется в
|
||||||
|
ядре Linux для UID. Там не~менее, очевидно, что контейнеры
|
||||||
|
должны поддерживать весь 16-битный диапазон~--- как минимум,
|
||||||
|
из-за +nobody+. (Если честно, я считаю выделение 64 тысяч
|
||||||
|
идентификаторов на контейнер оптимальным вариантом: верхние 16
|
||||||
|
бит из 32-битного UID можно использовать как идентификатор
|
||||||
|
контейнера, в том время как нижние будут соответствовать
|
||||||
|
идентификатору пользователя в этом контейнере\ldots{} Надеюсь,
|
||||||
|
вы не~потеряли нить рассуждений.) И, не~дожидаясь вашего
|
||||||
|
вопроса: пока нет никакого способа изменить этот диапазон~---
|
||||||
|
его границы заданы в исходном коде. Но когда-нибудь мы
|
||||||
|
обязательно добавим соответствующие настройки.
|
||||||
|
\item Вы можете поинтересоваться, что произойдет, если вы уже
|
||||||
|
используете идентификаторы из диапазона 61184--65519 для других
|
||||||
|
целей? systemd должен обработать такую ситуацию корректно, если
|
||||||
|
эти идентификаторы зарегистрированы в базе даных пользователей:
|
||||||
|
выбрав UID, systemd проверят, не~используется ли он кем-то, и
|
||||||
|
если он занят, выбирает другой~--- до тех пор, пока не~найдет
|
||||||
|
свободный. Проверка производится прежде всего при помощи
|
||||||
|
функций NSS. Также просматриваются списки объектов IPC, и
|
||||||
|
их владельцы проверяются на совпадение с нашим кандидатом. Таким
|
||||||
|
образом, systemd избегает использования UID, занятых кем-то еще.
|
||||||
|
Тем не~менее, это сокращает набор доступных идентификаторов, и в
|
||||||
|
худшем случае выделение пользователя может завершиться ошибкой
|
||||||
|
из-за отсутствия свободных UID в рабочем диапазоне.
|
||||||
|
\item Если имя для выделяемого пользователя не~указано явно, systemd
|
||||||
|
пытается вывести его из имени службы. Однако, далеко не~каждое
|
||||||
|
корректное имя службы является также корректным именем
|
||||||
|
пользователя, и чтобы обойти это, используется случайное имя.
|
||||||
|
Возможно, вам будет удобнее задать имя пользователя вручную~---
|
||||||
|
используйте для этого директиву +User=+.
|
||||||
|
\item \label{itm:setuser}
|
||||||
|
Если вы используете +User=+ в сочетании с +DynamicUser=on+, но
|
||||||
|
пользователь с указанным именем уже существует, то для службы
|
||||||
|
будет использован именно он, а механизм динамического выделения
|
||||||
|
пользователя для этой службы автоматически отключится. Таким
|
||||||
|
образом, упрощается переход между статическими и динамическими
|
||||||
|
пользователями: вы указываете нужное вам имя в +User=+, и пока
|
||||||
|
этот пользователь существует в системной базе, система будет
|
||||||
|
использовать его, и лишь при отутствии такого пользователя он
|
||||||
|
будет создаваться в динамическом режиме. Также это может быть
|
||||||
|
полезно в других ситуациях, например, чтобы подготовить службы,
|
||||||
|
использующие динамических пользователей, к возможности перехода
|
||||||
|
на статические UID, скажем, чтобы применить к ним квоты файловой
|
||||||
|
системы.
|
||||||
|
\item systemd всегда выделяет вместе с пользователем еще и группу, с
|
||||||
|
тем же самым значением идентификатора (UID = GID).
|
||||||
|
\item Если бы ядро Linux имело механизм наподобие +shiftfs+, то есть
|
||||||
|
способ смонтировать существующий каталог куда-либо с подменой
|
||||||
|
UID/GID по некоторому правилу, задаваемому при монтировании, это
|
||||||
|
значительно упростило бы реализацию работы +StateDirectory=+ в
|
||||||
|
сочетании с +DynamicUser=+, в частности, позволив отказаться от
|
||||||
|
рекурсивной смены владельца, и просто монтировать каталог с
|
||||||
|
хоста в пространство имен гостя, подменив владельца каталога на
|
||||||
|
UID/GID службы. Однако я не~питаю больших надежд на подобный
|
||||||
|
вариант, так как все работы в этой области сейчас завязаны на
|
||||||
|
пространство имен пользователей~--- механизм, который
|
||||||
|
\emph{никак не~используется} в обсуждаемой технологии (есть
|
||||||
|
мнение, что он создает гораздо больше проблем, чем решает, хотя
|
||||||
|
вы можете с этим и не~согласиться).
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
На сегодня все!
|
||||||
|
|
||||||
\appendix
|
\appendix
|
||||||
|
|
||||||
\section{FAQ (часто задаваемые вопросы)\sfnote{Перевод статьи
|
\section{FAQ (часто задаваемые вопросы)\sfnote{Перевод статьи
|
||||||
|
|||||||
Reference in New Issue
Block a user