Docker и SELinux
Опубликовано 27.7.2014 13:57 пользователем Peter Lemenkov
Мы уже упоминали про доклад Dan Walsh на тему Docker и SELinux, который он сделал на прошедшем DockerCon. Сразу после выступления, Dan написал статью, в которой тезисно изложил свой доклад.
Контейнеры не ограничивают
Я слышал и читал, что многие считают, что контейнеры Docker, это просто приложения в "песочнице", имея в виду, что можно спокойно запускать любые приложения в системе из-под рута внутри Docker-контейнера. Люди верят, что контейнеры защитят их систему в этом случае.
- Я слышал, как люди говорили, что контейнеры Docker настолько же безопасны, как и запуск приложений в отдельной виртуалке.
- Я знаю людей, которые загружают образы для Docker из интернета и запускают их.
- Я даже знаю PaaS-провайдеров (не OpenShift), позволяющих клиентам загружать их собственные образы, чтоб запускать их на системах совместного использования.
- У меня есть коллега, который сказал: "Docker предназначен для запуска под рутом неизвестно чьего ПО, скачанного из интернета."
— Ближе! Ближе, бандерлоги!
Немедленно прекратите считать, что Docker и ядро Linux защищают вас от вредоносного ПО.
Стоит ли вам беспокоиться?
Если вы не запускаете Docker на системах совместного использования, и если вы придерживаетесь общеизвестных правил безопасности, вам можно особо не волноваться. Просто всегда предполагайте, что привилегированные процессы внутри контейнера, это тоже самое, что и привилегированые процессы снаружи контейнера.
Некоторые ошибаются, считая, что контейнеры, это лучший и быстрый вариант виртуальных машин. С т.з. безопасности, контейнеры защищены гораздо слабее, о чем я скажу позже скажу.
С Docker-контейнерами стоит работать, как с "сервис-контейнерами" — это значит, что работать с Apache в контейнере точно так же, как с Apache, запущенном обычным способом. А это значит, что вам стоит поступать следующим образом:
- Сбрасывать привилегии, как только можно.
- Запускать сервисы не от root всегда, когда возможно.
- Рассматривать привилегии суперпользователя внутри контейнера, как root снаружи контейнера.
Сейчас мы рекомендуем участникам Common Criteria рассматривать привилегированные процессы в контейнере, точно также, как привилегированные процессы снаружи контейнера.
Не запускайте скачанные откуда-то образы для Docker на вашей системе. Я вижу множество схожестей между контейнерной революцией Docker и Linux-революцией 1999 года. В то время (да, и к сожалению сейчас - прим. перев.), когда сисадмин узнавал про интересное Linux-приложение, он обычно:
- Искал в интернете пакет по ресурсам типа rpmfind.net, или вовсе по случайным сайтам.
- Скачивал неизвестно кем и когда собранный пакет.
- Устанавливал с помощью пакетного менеджера (или make install)
- Запускал прямо под рутом
Что может пойти не так?
Типичный случай - спустя две недели после того, как сисадмин узнавал про уязвимость, скажем в zlib, и пока искал надеясь и веря, что его ПО неподвержено этой уязвимости, оно на самом деле еще как уязвимо.
Вот тут как раз и место и время, где Red Hat и несколько других игроков, которым доверяют, вступают в игру. Red Hat Enterprise Linux дает сисадминам:
- Доверенный репозиторий, откуда можно скачивать ПО.
- Своевременные исправления безопасности.
- Команда Red Hat для поиска и исправления уязвимостей.
- Команда инженеров для управления/поддержке пакетов и внедрения улучшений безопасности.
- Сертификации системы по безопасности.
Запускайте только контейнеры полученные из доверенных источников. Я считаю, что вам следует продолжать пользоваться пакетами и кодом, полученными из тех же мест, что вы использовали раньше. Если же вы получили код не от этих источников, то не надейтесь, что контейнеры защитят вашу систему.
Так в чем же проблема? Почему контейнеры не ограничивают?
Основная проблема в том, что не все в Linux может быть разнесено по различным пространствам имен (namespace). Сейчас Docker использует пять namespace, для разделения процессов - Process, Network, Mount, Hostname, Shared Memory.
Хотя эти пять пространств имен дают нам некоторый уровень безопасности, он далеко не максимальный, как в случае KVM. В случае виртуальной машины, процессы не общаются с ядром хостовой системы непосредственно. Они не имеют доступа к файловым системам ядра, таким как /sys, /sys/fs, /proc/*.
Device nodes общаются лишь с ядром виртуалки, не с хостом. Поэтому, для повышения привилегий до выхода из виртуалки, процессу требуется взломать ядро виртуалки, затем найти уязвимость в гипервизоре, затем пробиться сквозь SELinux (sVirt), жестко контролирующий виртуалку, а уж затем начинать атаковать ядро хостовой системы.
Когда же вы запустили процесс в контейнере, он уже имеет доступ к хостовому ядру.
Основные подсистемы ядра, которые до сих пор не поддерживают namespace:
- SELinux
- Cgroups
- /sys
- /proc/sys, /proc/sysrq-trigger, /proc/irq, /proc/bus
Устройства, которые не поддерживают namespace:
- /dev/mem
- /dev/sd*
- модули ядра
Если вы можете атаковать любой из вышеперечисленных компонентов, вы можете захватить контроль над хостом.