Docker: user namespaces
С самого начала пользователей Докера, обеспокоенных вопросами безопасности, волновал тот факт, что внутри контейнеров идентификаторы пользователей и групп начинаются с нуля. Иными словами, root
в контейнере равносилен root
-у во внешней системе. И даже нашлись сценарии (не самые тривиальные, конечно), в которых root
выбирается наружу.
В Docker 1.10 добавили поддержку так называемых user namespaces, которые призваны исправить эту ситуацию.
Нужно ли скорее бежать и включать их у себя?
Не спешите! Во всей этой истории предполагается, что зловредный пользователь контейнера хочет атаковать внешнюю систему. Такое возможно в сценариях хостинга и аренды. Если же вы используете Docker сами и на своих серверах, то, конечно же, не будете этого делать, а наоборот будете соблюдать правила безопасности внутри контейнеров. “Внутренний” root
заслуживает такого же бережного обращения как и внешний.
Внимание: глобальная настройка!
User namespaces — не та опция, с которой можно легко побаловаться. Из-за технических особенностей (а именно — из-за желания избежать копирования больших объемов данных и выставления этим копиям chown
) включение, выключение или изменение настроек user namespaces предполагает рестарт Docker engine, повторное вытягивание всех образов и, как следствие, запуск с чистого листа всех контейнеров.
Как это работает?
Итак, полезли в технические дебри.
В современных Линуксах для всех пользователей и групп, чьи идентификаторы попадают в интервалы UID_MIN - UID_MAX
и GID_MIN - GID_MAX
соответственно, выделяются диапазоны из SUB_UID_COUNT
и SUB_GID_COUNT
штук так называемых subordinate-идентификаторов. Они записываются в файлы /etc/subuid
и /etc/subgid
, и принимают значения от SUB_UID_MIN
до SUB_UID_MAX
и от SUB_GID_MIN
до SUB_GID_MAX
. Кто не понял — я не виноват 😃
Значения констант можно подсмотреть в man useradd
.
Вот так может выглядеть файл /etc/subuid
:
user1:100000:65536
user2:165536:65536
Для включения поддержки user namespaces Docker запускается с параметром --userns-remap=user
(если user
опустить или задать в default
, то будет создана специальная учетная запись с именем dockremap
).
Суть: subuid
и subgid
этого пользователя будут прибавляться ко всем uid
и gid
внутри контейнеров.
Папка с данными Докера переедет из /var/lib/docker
в /var/lib/docker/(subuid):(subgid)
.
root
внутри контейнеров для внешней системы будет выглядеть как subordinate-пользователь, и возможность “рутования” наружу будет предотвращена. (Ура!)
Ограничения и особенности
User namespaces несовместимы с некоторыми другими настройками (см. User namespace known limitations) и осложняют монтирование внешних директорий (см. обсуждение на StackOverflow).