Изолируйте контейнеры с пространством имён пользователя

Пространства имён Linux обеспечивают изоляцию запущенных процессов, ограничивая их доступ к системным ресурсам, при этом работающий процесс не знает об ограничениях. Дополнительные сведения о пространствах имён Linux см. в статье Пространства имён Linux.

Лучший способ предотвратить атаки с повышением привилегий изнутри контейнера — настроить приложения вашего контейнера для запуска от имени непривилегированных пользователей. Для контейнеров, процессы которых должны выполняться от имени пользователя root внутри контейнера, вы можете повторно сопоставить этого пользователя с менее привилегированным пользователем на хосте Docker. Сопоставленному пользователю назначается диапазон UID, которые функционируют в пространстве имён как обычные UID от 0 до 65536, но не имеют привилегий на самом хост-компьютере.

О переназначении и подчинении идентификаторов пользователей и групп

Само переназначение обрабатывается двумя файлами: /etc/subuid и /etc/subgid. Каждый файл работает одинаково, но один связан с диапазоном идентификаторов пользователей, а другой — с диапазоном идентификаторов групп. Рассмотрим следующую запись в /etc/subuid:

testuser:231072:65536

Это означает, что testuser назначается подчиненному диапазону идентификаторов пользователей из 231072 и следующих 65536 целых чисел в последовательности. UID 231072 отображается в пространстве имён (в данном случае внутри контейнера) как UID 0 (root). UID 231073 отображается как UID 1 и так далее. Если процесс пытается повысить привилегии за пределами пространства имён, процесс выполняется как непривилегированный UID с большим числом на хосте, который даже не сопоставляется с реальным пользователем. Это означает, что процесс вообще не имеет привилегий в хост-системе.

Примечание

Несколько диапазонов

Можно назначить несколько подчиненных диапазонов для данного пользователя или группы, добавив несколько непересекающихся сопоставлений для одного и того же пользователя или группы в файле /etc/subuid или /etc/subgid. В этом случае Docker использует только первые пять сопоставлений в соответствии с ограничением ядра только пятью записями в /proc/self/uid_map и /proc/self/gid_map.

Когда вы настраиваете Docker для использования функции userns-remap, вы можете дополнительно указывает существующего пользователя и/или группу или указывает default. Если вы укажете default, для этой цели будут созданы и использованы пользователь и группа dockremap.

Предупреждение

Некоторые дистрибутивы, такие как RHEL и CentOS 7.3, не добавляют новую группу автоматически в файлы /etc/subuid и /etc/subgid. В этом случае вы несете ответственность за редактирование данных файлов и назначение непересекающихся диапазонов. Данный шаг описан в Предпосылки.

Очень важно, чтобы диапазоны не перекрывались, чтобы процесс не мог получает доступ к другому пространству имён. В большинстве дистрибутивов Linux системные утилиты управляют диапазонами для вас, когда вы добавляете или удаляете пользователей.

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

Предпосылки

  1. Подчиненные диапазоны UID и GID должны быть связаны с существующим пользователем, даже если связь является деталью реализации. Пользователь владеет каталогами хранилища с пространством имён под номером /var/lib/docker/. Если вы не хотите использовать существующего пользователя, Docker может создать его для вас и использовать его. Если вы хотите использовать существующее имя пользователя или идентификатор пользователя, они уже должны существовать. Как правило, это означает, что соответствующие записи должны быть в /etc/passwd и /etc/group, но если вы используете другую серверную часть проверки подлинности, это требование может интерпретироваться иначе.

    Чтобы убедиться в этом, используйте команду id:

    $ id testuser
    
    uid=1001(testuser) gid=1001(testuser) groups=1001(testuser)
    
  2. Способ переназначения пространства имён обрабатывается на хосте с использованием двух файлов, /etc/subuid и /etc/subgid. Данные файлы обычно управляются автоматически при добавлении или удалении пользователей или групп, но в некоторых дистрибутивах, таких как RHEL и CentOS 7.3, вам может потребоваться управлять этими файлами вручную.

    Каждый файл содержит три поля: имя пользователя или идентификатор пользователя, за которым следует начальный UID или GID (который рассматривается как UID или GID 0 в пространстве имён) и максимальное количество UID или GID, доступных пользователю. Например, учитывая следующую запись:

    testuser:231072:65536
    

    Это означает, что процессы в пространстве имён пользователя, запущенные testuser, принадлежат хосту с UID 231072 (который внутри пространства имён выглядит как UID 0) до 296607 (231072 + 65536 — 1). Данные диапазоны не должны перекрываться, чтобы гарантировать, что процессы с пространствами имён не смогут получает доступ к пространствам имён друг друга.

    После добавления пользователя проверяет /etc/subuid и /etc/subgid, чтобы узнать, есть ли у вашего пользователя запись в каждом из них. Если нет, вам нужно добавить его, стараясь избежать дублирования.

    Если вы хотите использовать пользователя dockremap, автоматически созданного Docker, проверяет запись dockremap в данных файлах после настройки и перезапуска Docker.

  3. Если на хосте Docker есть какие-либо места, где непривилегированный пользователь должен писать, соответствующим образом настраивает разрешения для данных мест. Это также верно, если вы хотите использовать пользователя dockremap, автоматически созданного Docker, но вы не можете изменяет разрешения до тех пор, пока не настроите и не перезапустите Docker.

  4. Включение userns-remap эффективно маскирует существующие слои образов и контейнеров, а также другие объекты Docker в пределах /var/lib/docker/. Это связано с тем, что Docker необходимо настроить права собственности на данные ресурсы и фактически сохраняет их в подкаталоге в /var/lib/docker/. Лучше всего включить эту функцию в новой установке Docker, а не в существующей.

    Точно так же, если вы отключает userns-remap, вы не сможете получает доступ ни к одному из ресурсов, созданных, пока он был включён.

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

Включает userns-remap на демоне

Вы можете запускает dockerd с флагом --userns-remap или выполняет эту процедуру для настройки демона с помощью файла конфигурации daemon.json. Рекомендуется метод daemon.json. Если вы используете флаг, используйте следующую команду в качестве модели:

$ dockerd --userns-remap="testuser:testuser"
  1. Отредактируйте /etc/docker/daemon.json. Предполагая, что файл ранее был пуст, следующая запись включает userns-remap, используя пользователя и группу с именем testuser. Вы можете обращаться к пользователю и группе по идентификатору или имени. Вам нужно только указывает имя или идентификатор группы, если они отличаются от имени или идентификатора пользователя. Если вы указываете имя или идентификатор пользователя и группы, разделяет их двоеточием (:). Все следующие форматы работают со значением, при условии, что UID и GID testuser равны 1001:

    • testuser

    • testuser:testuser

    • 1001

    • 1001:1001

    • testuser:1001

    • 1001:testuser

    {
      "userns-remap": "testuser"
    }
    

    Примечание

    Чтобы использовать пользователя dockremap и позволить Docker создать его для вас, устанавливает значение default, а не testuser.

    Сохраняет файл и перезапустите Docker.

  2. Если вы используете пользователя dockremap, убедиться, что Docker создал его с помощью команды id.

    $ id dockremap
    
    uid=112(dockremap) gid=116(dockremap) groups=116(dockremap)
    

    Убедиться, что запись добавлена в /etc/subuid и /etc/subgid:

    $ grep dockremap /etc/subuid
    
    dockremap:231072:65536
    
    $ grep dockremap /etc/subgid
    
    dockremap:231072:65536
    

    Если данные записи отсутствуют, отредактируйте файлы как пользователя root и назначает начальный UID и GID, которые являются наивысшими назначенными, плюс смещение (в данном случае 65536). Будьте осторожны, чтобы не допустить перекрытия диапазонов.

  3. Убедиться, что предыдущие образы недоступны, с помощью команды docker image ls. Вывод должен быть пустым.

  4. Запускает контейнер из образа hello-world.

    $ docker run hello-world
    
  5. Убедиться, что каталог с пространством имён существует в /var/lib/docker/ с именем UID и GID пользователя в пространстве имён, принадлежит этому UID и GID и не может быть прочитан группой или всем миром. Некоторые из подкаталогов по-прежнему принадлежат root и имеют другие разрешения.

    $ sudo ls -ld /var/lib/docker/231072.231072/
    
    drwx------ 11 231072 231072 11 Jun 21 21:19 /var/lib/docker/231072.231072/
    
    $ sudo ls -l /var/lib/docker/231072.231072/
    
    total 14
    drwx------ 5 231072 231072 5 Jun 21 21:19 aufs
    drwx------ 3 231072 231072 3 Jun 21 21:21 containers
    drwx------ 3 root   root   3 Jun 21 21:19 image
    drwxr-x--- 3 root   root   3 Jun 21 21:19 network
    drwx------ 4 root   root   4 Jun 21 21:19 plugins
    drwx------ 2 root   root   2 Jun 21 21:19 swarm
    drwx------ 2 231072 231072 2 Jun 21 21:21 tmp
    drwx------ 2 root   root   2 Jun 21 21:19 trust
    drwx------ 2 231072 231072 3 Jun 21 21:19 volumes
    

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

    Каталоги, принадлежащие переназначенному пользователю, используются вместо тех же каталогов непосредственно под /var/lib/docker/, а неиспользуемые версии (например, /var/lib/docker/tmp/ в приведённом здесь примере) могут быть удалены. Docker не использует их, пока включён userns-remap.

Отключает переназначение пространства имён для контейнера

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

Чтобы отключить пользовательские пространства имён для определённого контейнера, добавляет флаг --userns=host в команду docker container create, docker container run или docker container exec.

Существует побочный эффект при использовании этого флага: переназначение пользователя не будет включено для этого контейнера, но, поскольку уровни только для чтения (образа) являются общими для контейнеров, право собственности на файловую систему контейнеров все равно будет переназначено.

Это означает, что вся файловая система контейнера будет принадлежать пользователю, указанному в конфигурации демона --userns-remap (231072 в приведённом выше примере). Это может привести к неожиданному поведению программ внутри контейнера. Например, sudo (который проверяет, что его двоичные файлы принадлежат пользователю 0) или двоичные файлы с флагом setuid.

Известные ограничения пространства имён пользователей

Следующие стандартные функции Docker несовместимы с запуском демона Docker с включенными пространствами имён пользователей:

  • совместное использование пространств имён PID или NET с хостом (--pid=host или --network=host).

  • внешние драйверы (тома или хранилища), которые не знают или не могут использовать сопоставления пользователей демона.

  • Использование флага режима --privileged для docker run без указания --userns=host.

Пространства имён пользователей — это расширенная функция, требующая координации с другими возможностями. Например, если тома монтируются с хоста, владение файлом должно быть заранее согласовано с необходимостью чтения или записи содержимого тома.

В то время как пользователь root внутри процесса-контейнера с пространством имён пользователя имеет многие ожидаемые привилегии суперпользователя в контейнере, ядро Linux накладывает ограничения, основанные на внутреннем знании того, что это процесс с пространством имён пользователя. Одним заметным ограничением является невозможность использования команды mknod. Отказано в разрешении на создание устройства в контейнере при запуске пользователем root.