12. К вопросу о безопасности

Одно из важнейших достоинств Unix-систем — концепция разделения привилегий между различными компонентами ОС. В частности, службы обычно работают от имени специальных системных пользователей, имеющих ограниченные полномочия, что позволяет уменьшить ущерб для системы в случае взлома этих служб.
Однако, такой подход предоставляет лишь самую минимальную защиту, так как системные службы, хотя уже и не получают полномочий администратора (root), все равно имеют практически те же права, что и обычные пользователи. Чтобы обеспечить более эффективную защиту, нужно поставить более жесткие ограничения, отняв у служб некоторые привилегии, присущие обычным пользователям. Такая возможность предоставляется системами мандатного контроля доступа (далее MAC, от Mandatory Access Control), например, SELinux. Если вам нужно обеспечить высокий уровень безопасности на своем сервере, то вам определенно стоит обратить свое внимание на SELinux. Что же касается systemd, то он предоставляет разработчикам и администраторам целый арсенал возможностей по ограничению локальных служб, и эти механизмы работают независимо от систем MAC. Таким образом, вне зависимости от того, смогли ли вы разобраться с SELinux — у вас появляется еще несколько инструментов, позволяющих повысить уровень безопасности.

В этой главе мы рассмотрим несколько таких опций, предоставляемых systemd, и обсудим вопросы их практического применения. Реализация этих опций основана на использовании ряда уникальных технологий безопасности, интегрированных в ядро Linux уже очень давно, но при этом практически неизвестных для большинства разработчиков. Мы постарались сделать соответствующие опции systemd максимально простыми в использовании, чтобы заинтересовать администраторов и апстримных разработчиков.
Вот краткий перечень наиболее интересных возможностей (в приведенном здесь списке не упомянута встроенная в systemd поддержка фильтров seccomp, так как она была добавлена уже после написания исходной статьи):

* Изолирование служб от сети.
* Предоставление службам независимых каталогов /tmp.
* Ограничение доступа служб к отдельным каталогам.
* Принудительное отключение полномочий (capabilities) для служб.
* Запрет форка, ограничение на создание файлов.
* Контроль доступа служб к файлам устройств.

Все эти опции описаны в man-страницах systemd, главным образом, в systemd.exec(5). Если вам потребуются какие-либо уточнения, пожалуйста, обратитесь к этим страницам.
Все эти опции доступны на системах с systemd, вне зависимости от использования SELinux или любой другой реализации MAC. Все эти опции не так уж и обременительны, и поэтому их разумнее будет использовать даже в тех случаях, когда явная необходимость в них, казалось бы, отсутствует. Например: даже если вы полагаете, что ваша служба никогда не пишет в каталог /tmp, и поэтому использование PrivateTmp=yes (см. ниже) вроде бы и не обязательно — лучше включить эту опцию, просто потому, что вы не можете знать наверняка, как будут вести себя используемые вами сторонние библиотеки (и плагины для них). В частности, вы никогда не узнаете, какие модули NSS могут быть включены в каждой конкретной системе, и пользуются ли они каталогом /tmp. Мы надеемся, что перечисленные опции окажутся полезными как для администраторов, защищающих свои системы, так и для апстримных разработчиков, желающих сделать свои службы безопасными «из коробки». Мы настоятельно рекомендуем разработчикам использовать такие опции по умолчанию в апстримных service-файлах — это сравнительно несложно, но дает значительные преимущества в плане безопасности.

12.1 Изолирование служб от сети
Простая, но мощная опция, которой вы можете воспользоваться при настройке службы — PrivateNetwork=:


...
[Service]
ExecStart=...
PrivateNetwork=yes
...


Добавление этой строчки обеспечивает полную изоляцию от сети всех процессов данной службы. Они будут видеть лишь интерфейс обратной петли (lo), причем полностью изолированный от обратной петли основной системы. Чрезвычайно эффективная защита против сетевых атак.
Предупреждение: Некоторым службам сеть необходима для нормальной работы. Разумеется, никто и не говорит о том, чтобы применять PrivateNetwork=yes к сетевым службам, таким, как Apache. Однако даже те службы, которые не ориентированы на сетевое взаимодействие, могут нуждаться в сети для нормального функционирования, и порой эта потребность не вполне очевидна. Например, если ваша система хранит учетные записи пользователей в базе LDAP, для выполнения системных вызовов наподобие getpwnam() может потребоваться обращение к сети. Впрочем, даже в такой ситуации, как правило, можно использовать PrivateNetwork=yes, за исключением случаев, когда службе может потребоваться информация о пользователях с UID ≥ 1000. Если вас интересуют технические подробности: эта возможность реализована с использованием технологии сетевых пространств имен (network namespaces). При задействовании данной опции, для службы создается новое пространство имен, в котором настраивается только интерфейс обратной петли.

12.2 Предоставление службам независимых каталогов /tmp
Еще одна простая, но мощная опция настройки служб — PrivateTmp=:


...
[Service]
ExecStart=...
PrivateTmp=yes
...


При задействовании этой опции, служба получит свой собственный каталог /tmp, полностью изолированный от общесистемного /tmp. По давно сложившейся традиции, в Unix-системах каталог /tmp является общедоступным для всех локальных служб и пользователей. За все эти годы, он стал источником огромного количества проблем безопасности. Чаще всего встречаются атаки с использованием символьных ссылок (symlink attacks) и атаки на отказ в обслуживании (DoS attacks). Использование независимой версии данного каталога для каждой службы делает подобные уязвимости практически бесполезными.
Для релиза Fedora 17 утверждена инициатива, направленная на включение этой опции по умолчанию для большинства системных служб. Предупреждение: Некоторые службы используют /tmp не по назначению, помещая туда сокеты IPC и другие подобные элементы, что само по себе уже является уязвимостью (хотя бы потому, что используемые при передаче информации файлы и каталоги должны иметь предсказуемые имена, что делает подобные службы уязвимыми к атакам через символьные ссылки и атакам на отказ в обслуживании). Подобные объекты лучше помещать в каталог /run, так как в нем присутствует строгое разделение доступа. В качестве примера такого некорректного использования /tmp можно привести X11, размещающий там свои коммуникационные сокеты (впрочем, в данном конкретном случае некоторые меры безопасности все же присутствуют: сокеты размещаются в защищенном подкаталоге, который создается на ранних стадиях загрузки).
Разумеется, для служб, использующих /tmp в целях коммуникации, включение опции PrivateTmp=yes недопустимо. К счастью, подобных служб сейчас уже не так уж и много.
Эта опция использует технологию пространств имен файловых систем (filesystem namespaces), реализованную в Linux. При включении данной опции, для службы создается новое пространство имен, отличающееся от иерархии каталогов основной системы только каталогом /tmp.

12.3 Ограничение доступа служб к отдельным каталогам
Используя опции ReadOnlyDirectories= и InaccessibleDirectories=, вы можете ограничить доступ службы к указанным каталогам только чтением, либо вообще запретить его:


...
[Service]
ExecStart=...
InaccessibleDirectories=/home
ReadOnlyDirectories=/var
...


Добавление этих двух строчек в файл конфигурации приводит к тому, что служба полностью утрачивает доступ к содержимому каталога /home (она видит лишь пустой каталог с правами доступа 000), а также не может писать внутрь каталога /var.
Предупреждение: К сожалению, в настоящее время опция ReadOnlyDirectories= не применяется рекурсивно к точкам монтирования, расположенным в поддереве указанного каталога (т.е. файловые системы, смонтированные в подкаталогах /var, попрежнему останутся доступными на запись, если, конечно, не перечислить их все поименно). Мы собираемся исправить это в ближайшее время.
Механизм работы этой опции тоже реализован с использованием пространств имен файловых систем.

12.4 Принудительное отключение полномочий (capabilities) для служб
Еще одна чрезвычайно эффективная опция — CapabilityBoundingSet=, позволяющая контролировать список capabilities, которые смогут получить процессы службы:


...
[Service]
ExecStart=...
CapabilityBoundingSet=CAP_CHOWN CAP_KILL
...


В нашем примере, служба может иметь лишь полномочия CAP_CHOWN и CAP_KILL. Попытки какого-либо из процессов службы получить любые другие полномочия, даже с использованием suid-бинарников, будут пресекаться. Список возможных полномочий приведен на странице документации capabilities(7). К сожалению, некоторые из них являются слишком общими (разрешают очень многое), например, CAP_SYS_ADMIN, однако выборочное делегирование полномочий все же является неплохой альтернативой запуску службы с полными административными (рутовыми) привилегиями.
Как правило, определение списка полномочий, необходимых для работы конкретной службы, является довольно трудоемким процессом, требующим ряда проверок. Чтобы немного упростить эту задачу, мы добавили возможность создания «черного списка» привилегий, как альтернативы описанному выше механизму «белого списка». Вместо того, чтобы указывать, какие привилегии можно оставить, вы можете перечислить, какие из них оставлять точно нельзя. Например: привилегия CAP_SYS_PTRACE, предназначенная для отладчиков, дает очень широкие полномочия в отношении всех процессов системы. Очевидно, что такие службы, как Apache, не занимаются отладкой чужих процессов, и поэтому мы можем спокойно отнять у них данную привилегию:


...
[Service]
ExecStart=...
CapabilityBoundingSet=~CAP_SYS_PTRACE
...


Наличие символа ~ после знака равенства инвертирует принцип работы опции: следующий за ним перечень привилегий рассматривается уже не как белый, а как черный список.
Предупреждение: Некоторые службы, при отсутствии определенных привилегий, могут вести себя некорректно. Как уже говорилось выше, формирование списка необходимых полномочий для каждой конкретной службы может оказаться довольно трудной задачей, и лучше всего будет обратиться с соответствующим запросом к разработчикам службы.
Предупреждение 2: Привилегии — отнюдь не лекарство от всех бед. Чтобы они работали действительно эффективно, возможно, придется дополнить их другими методиками защиты. Чтобы проверить, какие именно привилегии имеют сейчас ваши процессы, вы можете воспользоваться программой pscap из комплекта libcap-ng-utils. Применение опции CapabilityBoundingSet= является простой, прозрачной и удобной альтернативой введению аналогичных ограничений через модификацию исходного кода всех системных служб.

12.5 Запрет форка, ограничение на создание файлов
Некоторые меры безопасности можно ввести при помощи механизма ограничения ресурсов. Как следует из его названия, этот механизм предназначен прежде всего для контроля использования ресурсов, а не для контроля доступа. Однако, две его настройки могут быть использованы для запрета определенных действий: с помощью RLIMIT_NPROC можно запретить службе форкаться (запускать дополнительные процессы), а RLIMIT_FSIZE позволяет блокировать запись в файлы ненулевого размера:


...
[Service]
ExecStart=...
LimitNPROC=1
LimitFSIZE=0
...


Обратите внимание, что эти ограничения будут эффективно работать только в том случае, если служба запускается от имени простого пользователя (не root) и без привилегии CAP_SYS_RESOURCE (блокирование этой привилегии можно обеспечить, например, описанной выше опцией CapabilityBoundingSet=). В противном случае, ничто не мешает процессу поменять соответствующие ограничения.
Предупреждение: LimitFSIZE= действует очень жестко. Если процесс пытается записать файл ненулевого размера, он немедленно получает сигнал SIGXFSZ, который, как правило, прекращает работу процесса (в случае, если не назначен обработчик сигнала). Кроме того, стоит отметить, что эта опция не запрещает создание файлов нулевого размера.
Подробности об этих и других опциях ограничения ресурсов можно уточнить на странице документации setrlimit(2).

12.6 Контроль доступа служб к файлам устройств
Файлы устройств предоставляют приложениям интерфейс для доступа к ядру и драйверам. Причем драйверы, как правило, менее тщательно тестируются и не так аккуратно проверяются на предмет наличия уязвимостей, по сравнению с основными компонентами ядра. Именно поэтому драйверы часто становятся объектами атаки злоумышленников. systemd позволяет контролировать доступ к устройствам индивидуально для каждой службы:


...
[Service]
ExecStart=...
DeviceAllow=/dev/null rw
...


Приведенная конфигурация разрешит службе доступ только к файлу /dev/null, запретив доступ ко всем остальным файлам устройств. Реализация данной опции построена на использовании cgroups-контроллера devices.

12.7 Прочие настройки
Помимо приведенных выше, простых и удобных в использовании опций, существует и ряд других других настроек, позволяющих повысить уровень безопасности. Но для их использования, как правило, уже требуются определенные изменения в исходном коде службы, и поэтому такие настройки представляют интерес прежде всего для апстримных разработчиков. В частности, сюда относится опция RootDirectory= (позволяющая запустить службу chroot()-окружении), а также параметры User= и Group=, определяющие пользователя и группу, от имени которых работает служба. Использование этих опций значительно упрощает написание демонов, так как работа по понижению привилегий ложится на плечи systemd.

Возможно, у вас возникнет вопрос, почему описанные выше опции не включены по умолчанию. Отвечаем: чтобы не нарушать совместимость. Многие из них несколько отступают от традиций, принятых в Unix. Например, исторически сложилось, так что /tmp является общим для всех процессов и пользователей. Существуют программы, использующие этот каталог для IPC, и включение по умолчанию режима изоляции для /tmp нарушит работу таких программ.
И несколько слов в заключение. Если вы занимаетесь сопровождением unit-файлов в апстримном проекте или в дистрибутиве, пожалуйста, подумайте о том, чтобы воспользоваться приведенными выше настройками. Если сопровождаемая вами служба станет более защищенной в конфигурации по умолчанию («из коробки»), от этого выиграют не только ваши пользователи, но и все мы, потому что Интернет станет чуть более безопасным.

Содержание
Вперед - Отчет о состоянии службы и ее журнал
Назад - Службы с активацией в стиле inetd