diff --git a/s4a.tex b/s4a.tex index 655dee8..b92b3e7 100644 --- a/s4a.tex +++ b/s4a.tex @@ -1098,6 +1098,296 @@ systemd и на этот случай есть простое решение, и +systemctl start+ отменяет действия +systemctl stop+, +systemctl enable+ отменяет действие +systemctl disable+, а +rm+ отменяет действие +ln+. +\section{Смена корня} + +Практически все администраторы и разработчики рано или поздно встречаются с +\href{http://linux.die.net/man/1/chroot}{chroot-окружениями}. Системный вызов ++chroot()+ позволяет задать для определенного процесса (и его потомков) каталог, +который они будут рассматривать как корневой +/+, тем самым ограничивая для них +область видимости иерархии файловой системы отдельным поддеревом. Большинство +применений chroot-окружений можно отнести к двум классам задач: +\begin{enumerate} + \item Обеспечение безопасности. Потенциально уязвимый демон chroot'ится + в отдельный каталог, и даже в случае успешной атаки, взломщик + увидит лишь содержимое этого каталога, а не~всю файловую + систему~--- он окажется в ловушке chroot'а. + \item Подготовка и управление образом операционной системы при отладке, + тестировании, компиляции, установке или восстановлении. При этом + вся иерархия файловых систем гостевой ОС монтируется или + создается в каталоге системы-хоста, и при запуске оболочки (или + любого другого приложения) внутри этой иерархии, их корень + сдвигается в этот каталог. Система, которую <<видят>> такие + программы, может сильно отличаться от ОС хоста. Например, это + может быть другой дистрибутив, или даже другая аппаратная + архитектура (запуск i386-гостя на x86\_64-хосте). Гостевая ОС + не~может увидеть полной иерархии ОС хоста. +\end{enumerate} + +В системах, использующих классический SysV init, использовать chroot-окружения +сравнительно несложно. Например, чтобы запустить выбранного демона внутри +иерархии гостевой ОС, достаточно смонтировать внутри этой иерархии +/proc+, ++/sys+ и остальные API ФС, воспользоваться программой +chroot(1)+ для входа в +окружение, и выполнить соответствующий init-скрипт, запустив +/sbin/service+ +внутри окружения. + +Но в системах, использующих systemd, уже не~все так просто. Одно из важнейших +достоинств systemd состоит в том, что параметры среды, в которой запускаются +демоны, никак не~зависит от метода их запуска. В системах, использующих SysV +init, многие параметры среды выполнения (в частности, лимиты на системные +ресурсы, переменные окружения, и т.п.) наследуются от оболочки, из которой был +запущен init-скрипт. При использовании systemd ситуация меняется радикально: +пользователь просто уведомляет init-демона о необходимости запустить ту или иную +службу, и тот запускает демона в чистом, созданном <<с нуля>> и тщательно +настроенном окружении, параметры которого никак не~зависят от настроек среды, из +которой была отдана команда. Такой подход полностью отменяет традиционный метод +запуска демонов в chroot-окружениях: теперь демон порождается процессом init +(PID~1) и наследует корневой каталог от него, вне зависимости от того, находился +ли пользователь, отдавший команду на запуск, в chroot-окружении, или нет. Кроме +того, стоит особо отметить, что взаимодействие управляющих программ с systemd +происходит через сокеты, находящиеся в каталоге +/run/systemd+, так что +программы, запущенные в chroot-окружении, просто не~смогут взаимодействовать с +init-подсистемой (и это, в общем, неплохо, а если такое ограничение будет +создавать проблемы, его можно легко обойти, используя bind-монтирование). + +В свете вышесказанного, возникает вопрос: как правильно использовать +chroot-окружения в системах на основе systemd? Что ж, постараемся дать подробный +и всесторонний ответ на этот вопрос. + +Для начала рассмотрим первое из перечисленных выше применений chroot: изоляция в +целях безопасности. Прежде всего, стоит заметить, что защита, предоставляемая +chroot'ом, весьма эфемерна и ненадежна, так как chroot не~является <<дорогой с +односторонним движением>>. Выйти из chroot-окружения сравнительно несложно, и +соответствующее предупреждение даже +\href{http://linux.die.net/man/2/chroot}{присутствует на странице руководства}. +Действительно эффективной защиты можно достичь, только сочетая chroot с другими +методиками. В большинстве случаев, это возможно только при наличии поддержки +chroot в самой программе. Прежде всего, корректное конфигурирование +chroot-окружения требует глубокого понимания принципов работы программы. +Например, нужно точно знать, какие сокеты использует программа, чтобы обеспечить +bind-монтирование соответствующих каталогов. С учетом вышесказанного, +эффективный chroot-защита обеспечивается в том случае, когда она реализована в +коде самого демона. Именно разработчик лучше других знает (\emph{обязан знать}), +как правильно сконфигурировать chroot-окружение, и какой минимальный набор +файлов, каталогов и файловых систем необходим внутри для нормальной работы +демона. Уже сейчас существуют демоны, имеющие встроенную поддержку chroot. +К сожалению, в системе Fedora, установленной с параметрами по умолчанию, таких +демонов всего два: \href{http://avahi.org/}{Avahi} и RealtimeKit. Оба они +написаны одним очень хитрым человеком ;-) (Вы можете собственноручно +убедится в этом, выполнив команду +ls -l /proc/*/root+.) + +Возвращаясь к тема нашего обсуждения: разумеется, systemd позволяет помещать +выбранных демонов в chroot, и управлять ими точно так же, как и другими. +Достаточно лишь указать параметр +RootDirectory=+ в соответствующем +service-файле. Например: +\begin{Verbatim} +[Unit] +Description=A chroot()ed Service + +[Service] +RootDirectory=/srv/chroot/foobar +ExecStartPre=/usr/local/bin/setup-foobar-chroot.sh +ExecStart=/usr/bin/foobard +RootDirectoryStartOnly=yes +\end{Verbatim} + +Рассмотрим этот пример подробнее. Параметр +RootDirectory=+ задает каталог, в +который производится chroot перед запуском исполняемого файла, заданного +параметром +ExecStart=+. Заметим, что путь к этому файлу должен быть указан +относительно каталога chroot (так что, в нашем случае, с точки зрения основной +системы, на исполнение будет запущен файл +/srv/chroot/foobar/usr/bin/foobard+). +Перед запуском демона будет вызван сценарий оболочки +setup-foobar-chroot.sh+, +который должен обеспечить подготовку chroot-окружения к запуску демона +(например, смонтировать в нем +/proc+ и/или другие файловые системы, необходимые +для работы демона). Указав +RootDirectoryStartOnly=yes+, мы задаем, что ++chroot()+ будет выполняться только перед выполнением файла из +ExecStart=+, а +команды из других директив, в частности, +ExecStartPre=+, будут иметь полный +доступ к иерархии файловых систем ОС (иначе наш скрипт просто не~сможет +выполнить bind-монтирование нужных каталогов). Более подробную информацию по +опциям конфигурации вы можете получить на +\href{http://0pointer.de/public/systemd-man/systemd.service.html}{страницах} +\href{http://0pointer.de/public/systemd-man/systemd.exec.html}{руководства}. + +Поместив приведенный выше текст примера в файл ++/etc/systemd/system/foobar.service+, вы сможете запустить chroot'нутого демона +командой +systemctl start foobar.service+. Информацию о его текущем состоянии +можно получить с помощью команды +systemctl status foobar.service+. Команды +управления и мониторинга службы не~зависят от того, запущена ли она в chroot'е, +или нет. Этим systemd отличается от класического SysV init. + +Новые ядра Linux поддерживают возможность создания независимых пространств имен +файловых систем (в дальнейшем FSNS, от <>). По +функциональности этот механизм аналогичен +chroot()+, однако предоставляет +гораздо более широкие возможности, и в нем отсутствуют проблемы с безопасностью, +характерные для chroot. systemd позволяет использовать при конфигурировании +юнитов некоторые возможности, предоставляемые FSNS. В частности, использование +FSNS часто является гораздо более простой и удобной альтернативой созданию +полноценных chroot-окружений. Используя директивы +ReadOnlyDirectories=+, ++InaccessibleDirectories=+, вы можете задать ограничения по использованию +иерархии файловых систем для заданной службы: ее корнем будет системный корневой +каталог, однако указанные в этих директивах подкаталоги будут доступны только +для чтения или вообще недоступны для нее. Например: +\begin{Verbatim} +[Unit] +Description=A Service With No Access to /home + +[Service] +ExecStart=/usr/bin/foobard +InaccessibleDirectories=/home +\end{Verbatim} + +Такая служба будет иметь доступ ко всей иерархии файловых систем ОС, с +единственным исключением~--- она не~будет видеть каталог +/home+, что позволит +защитить данные пользователей от потенциальных хакеров. (Подробнее об этих +опциях можно почитать на +\href{http://0pointer.de/public/systemd-man/systemd.exec.html}{странице +руководства}). + +Фактически, FSNS по множеству параметров превосходят +chroot()+. Скорее всего, +Avahi и ReltimeKit в ближайшем будущем перейдут с +chroot()+ к использованию +FSNS. + +Итак, мы рассмотрели вопросы использования chroot для обеспечения безопасности. +Переходим ко второму пункту: Подготовка и управление образом операционной +системы при отладке, тестировании, компиляции, установке или восстановлении. + +chroot-окружения, по сути, весьма примитивно: они изолируют только иерархии +файловых систем. Даже после chroot'а в определенный подкаталог, процесс +по-прежнему имеет полный доступ к системным вызовам, может убить любой процесс +из основной системы, и т.п. Вследствие этого, запуск полноценной ОС (или ее +части) внутри chroot'а несет угрозу для хост-системы: у гостя и хоста отличаются +лишь содержимое файловой системы, все остальное у них общее. Например, если вы +обновляете дистрибутив, установленный в chroot-окружении, и пост-установочный +скрипт пакета отправляет +SIGTERM+ процессу init для его +перезапуска\footnote{Прим. перев.: Во избежание путаницы отметим, что перезапуск +процесса init (PID~1) <<на лету>> при получении +SIGTERM+ поддерживается только +в systemd, в классическом SysV init такой возможности нет}, на него среагирует +именно хост-система! Кроме того, хост и chroot'нутая система будут иметь общую +разделяемую память SysV (SysV shared memory), общие сокеты из абстрактных +пространств имен (abstract namespace sockets) и другие элементы IPC. Для +отладки, тестирования, компиляции, установки и восстановлении ОС не~требуется +абсолютно безопасная изоляция, однако нужна защита от \emph{случайного} +воздействия на ОС хоста изнутри chroot-окружения, иначе вы можете получить целый +букет проблем, как минимум, от пост-инсталляционных скриптов при установке +пакетов в chroot-окружении. + +systemd имеет целый ряд возможностей, полезных для работы с chroot-системами: + +Прежде всего, управляющая программа +systemctl+ автоматически определяет, что +она запущена в chroot-системе. В такой ситуации будут работать только команды ++systemctl enable+ и +systemctl disable+, во всех остальных случаях +systemctl+ +просто не~будет ничего делать, возвращая код успешного завершения операции. +Таким образом, пакетные скрипты смогут включить/отключить запуск <<своих>> служб +при загрузке (или в других ситуациях), однако команды наподобие ++systemctl restart+ (обычно выполняется при обновлении пакета) не~дадут никакого +эффекта внутри chroot-окружения\footnote{Прим. перев.: автор забывает отметить +не~вполне очевидный момент: такое поведение +systemctl+ проявляется только в +<<мертвых>> окружениях, т.е. в тех, где не~запущен процесс init, и +соответственно отсутствуют управляющие сокеты в +/run/systemd+. Такая ситуация +возникает, например, при установке системы в chroot через +debootstrap/febootstrap. В этом случае возможности +systemctl+ ограничиваются +операциями с символьными ссылками, определяющими триггеры активации юнитов, т.е. +выполнением действий +enable+ и +disable+, не~требующих непосредственного +взаимодействия с процессом init}. + +Однако, куда более интересные возможности предоставляет программа +\href{http://0pointer.de/public/systemd-man/systemd-nspawn.html}{systemd-nspawn}, +входящая в стандартный комплект поставки systemd. По сути, это улучшенный аналог ++chroot(1)+~--- она не~только подменяет корневой каталог, но и создает отдельные +пространства имен для дерева файловых систем (FSNS) и для идентификаторов +процессов (PID NS), предоставляя легковесную реализацию системного +контейнера\footnote{Прим. перев.: Используемые в +systemd-nspawn+ механизмы +ядра Linux, такие, как FS NS и PID NS, также лежат в основе +\href{http://lxc.sourceforge.net/}{LXC}, системы контейнерной изоляции для +Linux, которая позиционируется как современная альтернатива классическому +\href{http://wiki.openvz.org/Main_Page}{OpenVZ}. Стоит отметить, что LXC +ориентирована прежде всего на создание независимых виртуальных окружений, +с поддержкой раздельных сетевых стеков, ограничением на ресурсы, сохранением +настроек и т.п., в то время как +systemd-nspawn+ является лишь более удобной и +эффективной заменой команды +chroot(1)+, предназначенной прежде всего для +развертывания, восстановления, сборки и тестирования операционных систем. Далее +автор разъясняет свою точку зрения на этот вопрос}. ++systemd-nspawn+ проста в использовании как +chroot(1)+, однако изоляция +от хост-системы является более полной и безопасной. Всего одной командой +вы можете загрузить внутри контейнера \emph{полноценную} ОС (на базе systemd +или SysV init). Благодаря использованию независимых пространств идентификаторов +процессов, процесс init внутри контейнера получит PID~1, что позволит работать +ему в штатном режиме. Также, в отличие от +chroot(1)+, внутри окружения +будут автоматически смонтированы +/proc+ и +/sys+. + +Следующий пример иллюстрирует возможность запустить Debian в на Fedora-хосте +всего тремя командами: +\begin{Verbatim} +# yum install debootstrap +# debootstrap --arch=amd64 unstable debian-tree/ +# systemd-nspawn -D debian-tree/ +\end{Verbatim} + +Вторая из этих команд обеспечивает развертывание в подкаталоге +./debian-tree/+ +файловой структуры дистрибутива Debian, после чего третья команда запускает +внутри полученной системы процесс командной оболочки. Если вы хотите запустить +внутри контейнера полноценную ОС, воспользуйтесь командой +\begin{Verbatim} +# systemd-nspawn -D debian-tree/ /sbin/init +\end{Verbatim} + +После быстрой загрузки вы получите приглашение оболочки, запущенной внутри +полноценной ОС, функционирующей в контейнере. Изнутри контейнера невозможно +увидеть процессы, которые находятся вне его. Контейнер сможет пользоваться сетью +хоста, однако не~имеет возможности изменить ее настройки (это может привести к +серии ошибок в процессе загрузки гостевой ОС, но ни~одна из этих ошибок +не~должна быть критической). Контейнер получает доступ к +/sys+ и +/proc/sys+, +однако, во избежание вмешательства контейнера в конфигурацию ядра и аппаратного +обеспечения хоста, эти каталоги будут смонтированы только для чтения. Обратите +внимание, что эта защита блокирует лишь \emph{случайные}, \emph{непредвиденные} +попытки изменения параметров. При необходимости, процесс внутри контейнера, +обладающий достаточными полномочиями, сможет перемонтировать эти файловые +системы в режиме чтения-записи. + +Итак, что же такого хорошего в +systemd-nspawn+? +\begin{enumerate} + \item Использовать эту утилиту очень просто. Вам даже не~нужно вручную монтировать + внутри окружения +/proc+ и +/sys+~--- она сделает это за вас, а + ядро автоматически отмонтирует их, когда последний процесс + контейнера завершится. + \item Обеспечивается надежная изоляция, предотвращающая случайные + изменения параметров ОС хоста изнутри контейнера. + \item Теперь вы можете загрузить внутри контейнера полноценную ОС, а + не~одну-единственную оболочку. + \item Эта утилита очень компактна и присутствует везде, где установлен + systemd. Она не~требует специальной установки и настройки. +\end{enumerate} + +systemd уже подготовлен для работы внутри таких контейнеров. Например, когда +подается команда на выключение системы внутри контейнера, systemd на последнем +шаге вызывает не~+reboot()+, а просто +exit()+. + +Стоит отметить, что +systemd-nspawn+ все же не~является полноценной системой +контейнерной виртуализации/изоляции~--- если нужно именно это, воспользуйтесь +\href{ http://lxc.sourceforge.net/}{LXC}. Этот проект использует те же самые +механизмы ядра, но предоставляет куда более широкие возможности, включая +виртуализацию сети. Если вам угодно, +systemd-nspawn+ как реализация контейнера +похожа на GNOME~3~--- компактна и проста в использовании, опций для настройки +очень мало. В то время как LXC больше похож на KDE: опций для настройки больше, +чем строк кода. Я создал +systemd-nspawn+ специально для тестирования, отладки, +сборки, восстановления. Именно для этих задач вам стоит ее использовать~--- она +неплохо с ними справляется, куда лучше, чем +chroot(1)+. + +Что ж, пора заканчивать. Итак: +\begin{enumerate} + \item Использование +chroot()+ для обеспечения безопасности дает + наилучший результат, когда оно реализовано непосредственно в + коде самой программы. + \item +ReadOnlyDirectories=+ и +InaccessibleDirectories=+ могут быть + удобной альтернативой созданию полноценных chroot-окружений. + \item Если вам нужно поместить в chroot-окружение какую-либо службу, + воспользуйтесь опцией +RootDirectory=+. + \item +systemd-nspawn+~--- очень неплохая штука. + \item chroot'ы убоги, FSNS~--- + \href{http://ru.wikipedia.org/wiki/Leet}{1337}. +\end{enumerate} + +И все это уже сейчас доступно в Fedora~15. + \end{document} vim:ft=tex:tw=80:spell:spelllang=ru