Docker и SELinux

Мы уже упоминали про доклад 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*
  • модули ядра


Если вы можете атаковать любой из вышеперечисленных компонентов, вы можете захватить контроль над хостом.