Gymterview
middle

Как защитить Docker daemon?

Docker daemon (dockerd) работает с правами root и управляет всеми контейнерами на хосте. Компрометация Docker daemon эквивалентна полному контролю над хостом: злоумышленник может запускать произвольные контейнеры, читать данные из любых томов и выполнять команды на хосте. Поэтому защита daemon — одна из приоритетных задач безопасности.

1. Защита Docker socket:

По умолчанию Docker daemon слушает на Unix-сокете /var/run/docker.sock. Доступ к этому сокету равнозначен root-доступу к хосту, потому что через него можно запустить привилегированный контейнер с монтированием корневой файловой системы хоста.

Пример
# Проверить права на сокет
ls -la /var/run/docker.sock
# srw-rw---- 1 root docker 0 ... /var/run/docker.sock

# Только пользователи группы docker должны иметь доступ

Категорически запрещено монтировать Docker socket в production-контейнеры:

Пример
# ОПАСНО! Даёт контейнеру полный контроль над Docker daemon
volumes:
  - /var/run/docker.sock:/var/run/docker.sock

Если монтирование сокета необходимо (например, для CI runner), используйте read-only монтирование и авторизационные плагины для ограничения доступных операций.

2. Включение TLS для удалённого доступа:

Если Docker daemon должен быть доступен по сети (например, для удалённого управления), обязательна настройка mutual TLS (mTLS) — проверка и серверного, и клиентского сертификатов.

Пример
# Генерация CA (Certificate Authority)
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

# Генерация серверного ключа и сертификата
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=docker-host.bank.local" -sha256 \
    -new -key server-key.pem -out server.csr

echo subjectAltName = DNS:docker-host.bank.local,IP:10.0.1.100 >> extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf
openssl x509 -req -days 365 -sha256 \
    -in server.csr -CA ca.pem -CAkey ca-key.pem \
    -CAcreateserial -out server-cert.pem -extfile extfile.cnf

# Генерация клиентского ключа и сертификата
openssl genrsa -out client-key.pem 4096
openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile-client.cnf
openssl x509 -req -days 365 -sha256 \
    -in client.csr -CA ca.pem -CAkey ca-key.pem \
    -CAcreateserial -out client-cert.pem -extfile extfile-client.cnf

3. Безопасная конфигурация daemon.json:

Пример
{
  "tls": true,
  "tlscacert": "/etc/docker/certs/ca.pem",
  "tlscert": "/etc/docker/certs/server-cert.pem",
  "tlskey": "/etc/docker/certs/server-key.pem",
  "tlsverify": true,
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
  "icc": false,
  "userns-remap": "default",
  "no-new-privileges": true,
  "live-restore": true,
  "userland-proxy": false,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    }
  }
}

Назначение ключевых параметров:

Параметр Значение Описание
tlsverify: true Обязательная mTLS Клиент должен предоставить сертификат, подписанный доверенным CA. Без этого параметра любой может подключиться к daemon
icc: false Запрет Inter-Container Communication Контейнеры в одной bridge-сети не смогут общаться друг с другом напрямую — только через явно опубликованные порты (–link или docker network)
userns-remap: default Маппинг user namespace UID 0 (root) внутри контейнера маппится на непривилегированный UID на хосте (например, 100000). Даже при побеге из контейнера атакующий не получит root на хосте
no-new-privileges: true Запрет повышения привилегий Блокирует setuid/setgid-бинарники и другие механизмы повышения привилегий
live-restore: true Сохранение контейнеров при перезапуске daemon Контейнеры продолжают работать, даже если Docker daemon перезапускается (важно для обновлений без простоя)
userland-proxy: false Отключение userland-proxy Использование iptables вместо docker-proxy для маршрутизации портов — эффективнее и безопаснее

4. Docker Authorization Plugin:

Пример
{
  "authorization-plugins": ["casbin-authz-plugin"]
}

Authorization plugin — это webhook, который перехватывает каждый запрос к Docker daemon и применяет политики авторизации. Позволяет определять гранулярные правила: кто может запускать контейнеры, с какими параметрами (например, запретить --privileged или монтирование / хоста). Это особенно важно в средах с несколькими пользователями Docker.

5. Rootless Docker:

Пример
# Установка rootless Docker
dockerd-rootless-setuptool.sh install

# Docker daemon работает от обычного пользователя
export DOCKER_HOST=unix:///run/user/1000/docker.sock

Rootless Docker полностью исключает работу daemon от root — и сам daemon, и все контейнеры работают в user namespace непривилегированного пользователя. Это радикально снижает риск при компрометации daemon, но имеет ограничения: нельзя использовать некоторые storage drivers (overlay2 требует fuse-overlayfs), нет привязки к портам ниже 1024 без дополнительных настроек, невозможно использовать cgroup v1.

6. Ограничение логов (защита от заполнения диска):

Пример
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Без ограничений логи контейнера могут заполнить весь диск хоста, что приведёт к отказу в обслуживании всех контейнеров. Параметр max-size ограничивает размер одного файла лога, а max-file — количество ротируемых файлов. В данном примере максимальный объём логов на контейнер — 30 MB (3 файла по 10 MB).