воскресенье, 3 марта 2013 г.

systemd. Часть 3. Безопасность и ограничение использования ресурсов

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

1. Безопасность

1.1. Безопасность. chroot

Для запуска сервиса внутри chroot нужно вписать в раздел Service следующие параметры:

RootDirectory - изменённый корневой каталог (chroot),
ExecStartPre - команды, выполняемые до входа в chroot. Например, команды монтирования файловых систем /proc и /sys внутрь будущего корневого каталога сервиса, копирование внутрь chroot файлов, необходимых для работы сервиса.
RootDirectoryStartOnly - указывает, будут ли выполняться внутри chroot все команды (no), или только команда ExecStart (no).

Даже в случае запуска сервиса в chroot, сервисом можно продолжать управлять с помощью команды systemctl.

Стоит также помнить, что chroot не является наилучшим средством обеспечения безопасности, потому-что процесс, запущенный в chroot по прежнему имеет доступ ко всем идентификаторам процессов и имеет доступ ко всем системным вызовам системы, поэтому имеет возможность управлять процессами и даже может выйти за пределы chroot.

1.2. Безопасность. Пространства имён

Достойной альтернативой chroot может служить FSNS (Filesystem Namespace) - пространство имён файловых систем. С помощью FSNS можно сделать полностью недоступными или доступными только для чтения части файловой системы. Для этого можно воспользоваться следующими параметрами, которые нужно внести в раздел Service:

ReadOnlyDirectories - указанный каталог и все его подкаталоги будут доступны сервису только на чтение,
InaccessibleDirectories - указанный каталог и все его подкаталоги будут полностью недоступны сервису.

ПРЕДУПРЕЖДЕНИЕ: действие двух вышеописанных директив не распространяется на точки монтирования, попавшие внутрь указанных каталогов. Чтобы ограничить доступ сервиса к таким точкам монтирования, нужно задать дополнительный параметр с указанием точки монтирования.

Если сервису для выполнения его обязанностей не нужен доступ в сеть, можно запустить его в своей собственной изолированной сети, состоящей из одного интерфейса обратной петли, который будет изолирован от системного интерфейса обратной петли. Для этого достаточно указать в разделе Service всего один параметр:

PrivateNetwork - значение yes указывает необходимость запустить сервис в изолированной сети, а значение no позволит сервису использовать сетевые интерфейсы системы.

Если сервис не использует каталог /tmp для создания сокет-файлов, можно указать в разделе Service параметр, создающий для процесса изолированное пространство имён для каталога /tmp:

PrivateTmp - значение yes указывает на необходимость создать для сервиса изолированное пространство имён файловой системы с каталогом /tmp, а значение no позволит сервису пользоваться общесистемным каталогом /tmp.

Кроме вышеописанных настроек, работающих внутри service-файлов, в составе systemd имеется утилита systemd-nspawn, создающая полностью изолированное пространство имён. В нём автоматически будут смонтированы файловые системы /proc и /sys, будет создан изолированный интерфейс обратной петли и отдельное пространство имён для идентификаторов процессов. Внутри такого пространства имён можно даже запустить процесс с идентификатором 1, что позволяет запускать внутри него полноценную операционную систему, основанную на ядре Linux.

Например, воспользовавшись всего тремя командами можно запустить Debian поверх Fedora:
# yum install debootstrap
# debootstrap --arch=amd64 unstable debian-tree/
# systemd-nspawn -D debian-tree/ /sbin/init
В последней команде нужно указать процесс, который будет запущен внутри изолированного пространства имён. Если указать процесс init, как в примере выше, внутри запустится полный комплект сервисов. По умолчанию запускается интерпретатор shell.

Эта команда предназначена лишь для целей отладки и разработки и не может являться полноценной заменой для систем контейнерной изоляции вроде LXC, поскольку не имеет полноценных средств для ограничения использования системных ресурсов.

1.3. Безопасность. cgroups

Имеется возможность ограничить доступ сервиса к файлам устройств системы средствами cgroups. Для этого нужно указать параметр в разделе Service:

DeviceAllow - задаёт имя файла устройства и права доступа к нему: r - чтение файла устройства, w - запись в файл устройства, m - создание нового файла устройства. Например, параметр DeviceAllow=/dev/null rw разрешит сервису работать только с файлом устройства /dev/null, разрешая операции чтения и записи. Доступ к остальным устройствам будет полностью заблокирован.

1.4. Безопасность. capabilities

Для задания списка доступных полномочий (capabilities) сервиса можно воспользоваться следующим параметром, который необходимо поместить в раздел Service:

CapabilityBoundingSet - задаёт список разделённых пробелами разрешённых полномочий. Доступ к не указанным здесь полномочиям будет заблокирован. При необходимости задать список запрещённых полномочий, после знака равно и перед списком нужно поставить знак тильды. Доступ к не указанным в списке полномочиям в этом случае будет разрешён.

Список активных полномочий процессов можно увидеть с помощью команды pscap из пакета libcap-ng-utils.

2. Ограничение использования ресурсов

2.1. Ограничение использования ресурсов. rlimit

Ещё одна функция, которой обладает systemd - это возможность настраивать ограничения на использование ресурсов. Можно настроить любое ограничение, описанное в setrlimit(2). Для установки ограничения RLIMIT_NPROC нужно указать в разделе Service параметр LimitNPROC, а названия других параметров строятся по такой же схеме - префикс RLIMIT_ заменяется на Limit.

Стоит отметить, что ограничения эффективны лишь в том случае, если процесс не имеет полномочия CAP_SYS_RESOURCE и не запущен от имени пользователя root.

2.2. Ограничение использования ресурсов. cgroups

systemd использует две группы возможностей, предоставляемых cgroups - это:
1. группировка процессов для определения их принадлежности определённому сервису или сеансу пользователя,
2. ограничения на использование ресурсов системы сервисами и сеансами пользователей.

Первая группа возможностей необходима для нормального функционирования systemd, без неё возможности systemd будут сильно ограничены. Без второй группы возможностей systemd прекрасно обходится и она не обязательна для использования. Именно её мы сейчас и рассмотрим.

В cgroups имеется три контроллера, ограничивающих использование системных ресурсов: cpu - ограничивает использование процессоров системы, memory - ограничивает использование оперативной памяти системы, blkio - ограничивает использование пропускной полосы к блочным устройствам (дискам). По умолчанию в systemd используется только первый контроллер, который делит процессорное время поровну между всеми сервисами. В отличие от systemd, классический SysV init делит процессорное время поровну между всеми процессами, работающими в системе, так что сервис, состоящий из большего количества процессов, получает и больше процессорного времени.

Для просмотра текущего использования ресурсов системы сервисами можно воспользоваться командой systemd-cgtop. Поскольку по умолчанию в systemd включен только контроллер cpu, то используется общий учёт использования памяти и пропускной полосы к блочным устройствам для всех сервисов. При указании ограничений по использованию памяти или пропускной полосы к блочным устройствам хотя-бы в одном из service-файлов, systemd автоматически начинает использовать этот контроллер. Включить же его принудительно можно с помощью директивы DefaultControllers в файле /etc/systemd/system.conf.

Стоит отметить, что ограничение ресурсов обходится не бесплатно и может сказаться на общей производительности системы. Особенно в этом замечен контроллер memory, однако в будущих версиях ядер Linux всё может стать лучше.

Рассмотрим ограничения, предоставляемые каждым из контроллеров:

2.2.1. Процессор

CPUShares - количество долей процессорного времени, выделенных сервису. По умолчанию каждый сервис получает 1024 доли процессорного времени. Процессорное время распределяется между сервисами таким образом, что каждый сервис получит время прямо пропорциональное доли сервиса и обратно пропорциональное сумме долей всех сервисов.

2.2.2. Память

MemoryLimit - жёсткое ограничение по использованию памяти сервисом. Превышать этот лимит сервис не может,
MemorySoftLimit - мягкое ограничение по использованию памяти сервисом. Допускается превышение этого лимита, если в системе есть свободная память.

Оба параметра поддерживают суффиксы K, M, G и T, обозначающие, соответственно, килобайты, мегабайты, гигабайты и терабайты (Будьте добры, дайте пару планочек по 4 терабайта. Благодарю Вас, Вы очень любезны).

2.2.3. Ввод-вывод

BlockIOWeight - количество долей пропускной полосы, выделенных сервису для работы с блочными устройствами. Этот параметр может принимать значения от 10 до 1000, а по умолчанию принимает значение 1000,
BlockIOReadBandwidth - объём данных, который сервису разрешается прочитать с блочных устройств за одну секунду,
BlockIOWriteBandwidth - объём данных, который сервису разрешается записать на блочные устройства за одну секунду.

Абсолютные значения также поддерживают суффиксы K, M, G и T, обозначающие, соответственно, скорости обмена данными в килобайтах в секунду, мегабайтах секунду, гигабайтах в секунду и терабайтах в секунду (Отстой! Наш провайдер уже год петабайтные тарифы предоставляет).

В любом из параметров можно указать конкретное блочное устройство, доступ к которому регулируется. При указании каталога или файла, systemd самостоятельно определит, на каком блочном устройстве он располагается и выставит ограничения на это блочное устройство.

Примеры использования:
BlockIOWeight=500
BlockIOWeight=/dev/disk/by-id/ata-SAMSUNG_MMCRE28G8MXP-0VBL1_DC06K01009SE009B5252 750
BlockIOWeight=/home/lennart 750
BlockIOReadBandwidth=/var/log 5M
2.2.4. Другие параметры cgroups

ControlGroupAttribute - позволяет задать значение произвольного атрибута контрольной группы, для которого в systemd нет специально предусмотренного параметра.

Существует также набор параметров, действующих на уровне процессов, но не использующих возможностей cgroups и потому не требующих много ресурсов для их применения IOSchedulingClass, IOSchedulingPriority, CPUSchedulingPolicy, CPUSchedulingPriority, CPUAffinity, LimitCPU.

1 комментарий:

Анонимный комментирует...

Класс. Спасибо