Как защитить 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).