Перейти к содержанию

13. Соображения безопасности

Изоляция привилегий, поверхность атаки, Linux capabilities и безопасная эксплуатация

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

Чтобы выполнить chroot, процесс сначала нужно запустить от имени root. Создавать окружения chroot вручную и запускать процесс уже внутри них бессмысленно: их трудно создавать, их никогда не сопровождают должным образом, и ошибок в них всегда гораздо больше, чем в основной файловой системе. Кроме того, при компрометации злоумышленник сможет воспользоваться специально подготовленной файловой системой. К сожалению, многие администраторы путают «запустить от имени root» и «работать от имени root», из-за чего меняют UID ещё до запуска haproxy и тем самым ослабляют действующие ограничения безопасности.

HAProxy нужно запускать от имени root, чтобы:

  • изменять ограничения на число файловых дескрипторов;
  • привязываться к привилегированным портам;
  • привязываться к определённому сетевому интерфейсу;
  • прозрачно прослушивать чужой адрес;
  • изолировать себя в окружении chroot;
  • переходить на другой непривилегированный UID.

HAProxy может потребоваться работать от имени root, чтобы:

  • привязываться к интерфейсу для исходящих соединений;
  • привязываться к привилегированным исходным портам для исходящих соединений;
  • прозрачно привязываться к чужому адресу для исходящих соединений.

Большинству пользователей никогда не понадобится «работать от имени root». Однако «запуск от имени root» охватывает большинство сценариев использования.

Безопасная конфигурация содержит:

  • Директиву chroot, указывающую на пустой каталог без каких-либо прав доступа. Его можно подготовить следующей командой UNIX:
# mkdir /var/empty && chmod 0 /var/empty || echo "Failed"

и указать следующим образом в секции global конфигурации HAProxy:

chroot /var/empty
  • Обе директивы uid/user и gid/group в секции global:
user haproxy
group haproxy
  • Сокет stats, у которого mode, uid и gid соответствуют пользователю и/или группе, которым разрешён доступ к CLI, чтобы посторонние не могли получить к нему доступ:
stats socket /var/run/haproxy.stat uid hatop gid hatop mode 600

13.1. Поддержка Linux capabilities

Начиная с версии v2.9 haproxy поддерживает Linux capabilities. Если исполняемый файл собран с USE_LINUX_CAP=1, он может сохранять возможности, указанные в директиве ‘setcap’, при переходе от пользователя root к обычному пользователю.

Начиная с версии v3.1 haproxy также проверяет, установил ли администратор возможности из директивы ‘setcap’ в наборе Permitted его исполняемого файла (системный вызов capget). Если это так, он переносит эти возможности в набор Effective своего процесса (системный вызов capset), работая от имени обычного пользователя.

Это сделано, чтобы исключить все возможные случаи, когда haproxy запускается и работает от имени root: режим прозрачного прокси и привязку к привилегированным портам.

Директива ‘setcap’ поддерживает следующие сетевые возможности:

  • cap_net_admin: прозрачное проксирование, привязка сокета к определённому сетевому интерфейсу, использование действия set-mark;
  • cap_net_raw (подмножество cap_net_admin): прозрачное проксирование;
  • cap_net_bind_service: привязка сокета к определённому сетевому интерфейсу;
  • cap_sys_admin: создание сокета в определённом сетевом пространстве имён.

HAProxy никогда не переносит эти возможности из своего набора Permitted в Effective, если они не перечислены в аргументе ‘setcap’. Дополнительные сведения о директиве ‘setcap’ и поддерживаемых возможностях приведены в главе 3.1 «Управление процессами и безопасность» руководства по конфигурации.

Администратор может добавить необходимые возможности в набор Permitted исполняемого файла haproxy следующей командой:

Пример:

# setcap cap_net_admin,cap_net_bind_service=p /usr/local/sbin/haproxy

Добавленные возможности будут видны в наборе Permitted процесса после его запуска. Если те же возможности указаны в аргументах директивы ‘setcap’, они также могут быть видны в наборе Effective процесса. Это можно проверить следующей командой:

Пример:

# grep Cap /proc/<haproxy PID>/status
CapInh: 0000000000000000
CapPrm: 0000000000001400
CapEff: 0000000000001400
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000

Дополнительные сведения о setcap и наборах возможностей приведены в справочных страницах Linux (capabilities(7)).

В некоторых сценариях, например при прозрачном проксировании или создании сокета в определённом сетевом пространстве имён, парсер конфигурации определяет, что требуются cap_net_raw, cap_sys_admin или другие поддерживаемые возможности. Затем на этапе инициализации процесс haproxy проверяет, можно ли включить их в свой набор Effective. Если это невозможно из-за сбоя системного вызова capget или capset (например, из-за ограничений на системные вызовы, наложенных модулями безопасности SELinux, Seccomp и т. п.), процесс выводит диагностические предупреждения (при запуске с -dD).

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

Пример:

$ haproxy -dD -f haproxy.cfg
...
[ALERT]    (96797): Binding [haproxy.cfg:36] for frontend fe: cannot bind socket (Permission denied) for [0.0.0.0:80]
[ALERT]    (96797): [haproxy.main()] Some protocols failed to start their listeners! Exiting.