Статья 6 из 10, в которой речь пойдёт об LXC: linux capabilities, cgroups, AppArmor, SELinux, seccomp, пользовательское пространство имён.
Когда речь заходит о безопасности использования контейнеров, то люди склонны рассматривать их или небезопасными или безопасными по природе своей. Но реальность не чёрно-белая и LXC поддерживает ряд технологий, которые смягчают большинство опасений.
Самого начала хочется развенчать миф, дескать LXC безопасна только при условии использования привилегированных контейнеров. Стефан Грабер является мантейнером LXC в Ubuntu и даёт гарантии, что дефолтные шаблоны и сама Убунту-хост использует отличные конфигурации cgroup и профиля AppArmor, которые предотвращают все известные атаки на сегодняшний день.
Просто имейте в виду, что если используете непривилегированные контейнеры, не давайте root доступ в контейнере тому, кому не хотели бы дать root доступ к вашему хосту.
Первая фича безопасности основана на поддержке Linux capabilities. Можно указать какие возможности (capabilities) будут сброшены (drop) при старте контейнера ИЛИ указать список разрешённых (keep) возможностей, а все не указанные явно будут сброшены.
Для этих целей есть два параметра:
Весь список доступных возможностей можно узнать в man 7 capabilities
.
Вроде всё звучит радужно, как отличный способ сделать контейнеры безопасными и для определённых случаях это так. Во-первых, вскоре можно заметить, что некоторые сброшенные возможности не практичны. Во-вторых, следует знать, что root в контейнере может вернуть себе утраченные возможности.
В шаблоне Ubuntu по умолчанию используется lxc.cap.drop для сброса таких возможностей как sys_module, mac_admin, mac_override, sys_time. Это предотвращает некоторые известные проблемы при загрузке контейнера.
Контрольные группы интересны тем, что делают массу взаимосвязанных, но довольно разных вещей:
Первые два пункта не связаны с безопасностью, хотя квоты позволяют избежать DoS на хост, если установить лимиты на память, CPU и I/O. Последний пункт, касающийся devices cgroup, позволяет указать к каким символьным и блочным устройствам контейнер может получить доступ, и что он может сделать с ними. Можно ограничить создание, чтение и запись для каждой комбинации из старшего (major) и младшего (minor) чисел.
В LXC для настройки cgroup используется опция lxc.cgroup.*, которая должна быть определена полностью как
lxc.cgroup.<controller>.<key> = <value>
Для примера можно ограничить использование памяти контейнером p1.
lxc.cgroup.memory.limit_in_bytes = 134217728
Это установит лимит память в 128 Мб, которые указаны в байтах. Альтернативно можно указать лимиты через /sys/fs/cgroup/memory/lxc/p1/memory.limit_in_bytes
Большинство LXC шаблонов устанавливает только несколько записей
# Default cgroup limits
lxc.cgroup.devices.deny = a
## Allow any mknod (but not using the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
## /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
## consoles
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 5:1 rwm
## /dev/{,u}random
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 1:9 rwm
## /dev/pts/*
lxc.cgroup.devices.allow = c 5:2 rwm
lxc.cgroup.devices.allow = c 136:* rwm
## rtc
lxc.cgroup.devices.allow = c 254:0 rm
## fuse
lxc.cgroup.devices.allow = c 10:229 rwm
## tun
lxc.cgroup.devices.allow = c 10:200 rwm
## full
lxc.cgroup.devices.allow = c 1:7 rwm
## hpet
lxc.cgroup.devices.allow = c 10:228 rwm
## kvm
lxc.cgroup.devices.allow = c 10:232 rwm
Такая конфигурация разрешает контейнеру (точнее udev) создавать любое устройство по его желанию (разрешает маска m) и блокирует всё остальное по умолчанию (deny = a), если не указано ниже в allow. Обычно этого достаточно для типичной работы контейнера.
В LXC добавлена поддержка профилей AppArmor. Поддержка AppArmor проста! Есть опция в конфиге контейнера - lxc.aa_profile, которая указывает на профиль AppArmor. Профиль AppArmor предотвращает любую из известных попыток сбежать из контейнера и нанести вред хосту.
На сегодня, Ubuntu обладает 3 профилями:
Можно создать свои профили! Поместить их в /etc/apparmor.d/lxc/, перезагрузить sudo /etc/init.d/apparmor reload
и указывать имя профиля в опции lxc.aa_profile.
Поддержка SELinux подобна AppArmor'у. Контекст SELinux можно задать с помощью lxc.se_context.
Пример:
lxc.se_context = unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023
Как и в случае с AppArmor, LXC переключится на новый контекст перед стартом init в контейнере.
Seccomp - это фильтры безопасного вычисления (SECure COMPuting mode). Seccomp сравнительно недавно появившийся механизм, который позволяет фильтровать системные вызовы (syscalls). Можно написать свой файл политики для конкретного контейнера и тем самым позволять или запрещать системные вызовы.
Для примера возьмём бесполезный и ограниченный файл политики для seccomp:
1
whitelist
103
Здесь мы разрешаем только системный вызов #103 syslog в контейнере и запрещаем всё остальное. Seccomp является низкоуровневой "защитой" и полезна только в очень специфических случаях использования. Все системные вызовы должны быть адресованы по их ID, а не по их именам, но они меняются при смене архитектуры. Если у вас хост 64 битный, то при загрузке политики seccomp все 32 битные системные вызовы будут запрещены. Нужны универсальные seccomp профили, но пока это не первоочередная задача.
Последнее, но не менее важное, механизм, позволяющий реально сделать контейнеры безопасными. LXC поддерживает user namespace. Более подробно об этой возможности будет описано в следующей статье, но кратко говоря, LXC больше не работает от root'а и злоумышленник, осуществивший побег из контейнера, окажется обычным пользователем в хост-системе. Ну пробил ты головой стенку камеры и что делать в чужой темнице?
Предыдущая статья LXC 1.0: Хранилище контейнеров.
Следующая статья LXC 1.0: Непривилегированные контейнеры.
Дополнительные материалы:
Серия статей LXC 1.0. от Стефана Грабера.
Ubuntu будет более безопасной с seccomp фильтрами.
Безопасность Ubuntu.