Защита хоста Docker
Первая категория охватывает все, что вы можете сделать для защиты вашего хоста докеров.
1. Поддерживайте актуальность Docker Host
Здесь действительно не нужно никаких объяснений. Это самая простая из лучших практик безопасности Docker, и она буквально занимает секунды.
Держите свою хост-систему Docker в курсе обновлений безопасности. В моем стеке Docker Traefik на базе Linux я часто обновляю пакеты и обновляю систему, используя следующие команды:
sudo apt-get update
sudo apt-get upgrade
2. Используйте обратный прокси
Лучший способ — не открывать какие-либо порты для Интернета, а вместо этого использовать VPN в вашей частной сети и получать локальный доступ к приложениям. Но это слишком громоздко, и размещение приложений за обратным прокси-сервером — удобная, но худшая альтернатива.
Вам нужно будет настроить переадресацию портов на вашем интернет-шлюзе, чтобы перенаправить определенные порты на хост Docker.
Я настоятельно рекомендую не выставлять все приложения Docker в Интернет. Вместо этого поместите их за обратным прокси. Я использую Traefik и выставляю в Интернет только порты 80 и 443. Даже приборная панель traefik, использующая порт 8080, находится за обратным прокси-сервером.
Защита Докера
Следующая большая категория: Docker. Давайте рассмотрим, как я считаю, контрольный список безопасности Docker , чтобы убедиться, что ваша установка защищена.
3. Не меняйте владельца сокета Docker
Не связывайтесь с владением Docker Socket (/var/run/docker.sock
в Linux). По умолчанию сокет принадлежит пользователю root и группе docker .
Для удобства я рекомендовал добавить себя (ваше имя пользователя) в группу докеров в прошлом.
Преимущество заключается в том, что вы можете запускать команды docker без использования sudo. Но это угроза безопасности. Я отошел от него и не рекомендую.
4. Не запускайте контейнеры Docker от имени root
По умолчанию контейнеры запускаются от имени пользователя root внутри контейнера, что дает привилегии root. Это угроза безопасности.
Одна из лучших практик безопасности Docker — запускать контейнер от имени пользователя без полномочий root (UID не 0). Известные и надежные образы используют эту передовую практику безопасности при создании образов. Например, LinuxServer.io предоставляет образы докеров для нескольких приложений домашнего сервера. Их образы позволяют явно указать UID и GID в качестве переменных окружения.
В идеале, это должно выглядеть так, как показано в блоке кода ниже.
environment:
- PUID=$PUID
- PGID=$PGID
5. Осторожно используйте привилегированный режим
По умолчанию контейнеры Docker работают в «непривилегированном» режиме. Это означает, что эти контейнеры не могут запускать демон Docker внутри себя. Это также запрещает использование хост-устройств или определенных функций ядра.
Обычно это делается путем добавления следующей строки в services:
privileged: true
Для некоторых служб требуется привилегированный режим. Например, только четыре службы в моем файле компоновки Docker используют привилегированный режим:
- Home Assistant — для доступа к USB-контроллеру Z-wave.
- Socket Proxy — требование для Socket proxy, повышающее безопасность.
- Glances – для мониторинга системы
- APCUPSD — для связи демона ИБП APC с ИБП через USB.
В таких ситуациях используйте образы докеров только из надежных источников (подробнее об этом позже). Еще лучший подход — использовать возможности докеров .
Кроме того, добавление следующей строки гарантирует, что контейнеры не получат дополнительных привилегий:
security_opt:
- no-new-privileges:true
6. Используйте доверенные образы Docker
По возможности всегда используйте изображения от проверенных издателей или официальных источников.
Это дает немедленное доверие и обеспечивает безопасность контейнера Docker.
С непопулярными образами трудно предсказать или предположить, были ли соблюдены/реализованы передовые методы безопасности Docker.
Note
К сожалению, для многих приложений для домашних серверов, таких как Sonarr, Radarr и т. д., нет «официальных» или «проверенных» издателей. Поэтому вам придется ориентироваться на популярность изображения (количество загрузок/звезд).
7. Используйте секреты Docker
Указание всей вашей конфиденциальной информации (например, ключей API) в файле .env
, /etc/environment
или файле docker-compose.yml
может представлять угрозу безопасности.
Именно поэтому были введены секреты Docker: для управления конфиденциальными данными.
Реализация секретов Docker для вашего стека — это многоэтапный процесс.
А. Создать папку секретов
Сначала создайте папку secrets внутри корневой папки docker .
sudo mkdir secrets
Установите для этой папки права доступа 600 , принадлежащие пользователю root и группе root .
sudo chown root:root ~/docker/secrets
sudo chmod 600 ~/docker/secrets
B. Создайте секретные файлы
Затем вам нужно будет поместить вашу конфиденциальную информацию в файл. В качестве примера давайте определим секрет для электронной почты учетной записи Cloudflare.
Давайте создадим файл внутри папки секретов с именем cloudflare_email . Помните, что для создания файла вам потребуются root-права. В моей системе Ubuntu я использую:
sudo su
nano cloudflare_email
Единственное, что нужно добавить в файл, — это адрес электронной почты вашей учетной записи Cloudflare.
Сохранить и выйти.
C. Определите секреты в файле Docker Compose
Теперь, когда секрет Docker создан, давайте определим его в файле компоновки Docker. Делается это с помощью блока: secrets.
В приведенном ниже примере показаны два секрета: cloudflare_email
и cloudflare_api_key
.
########################### SECRETS
secrets:
cloudflare_email:
file: $SECRETSDIR/cloudflare_email
cloudflare_api_key:
file: $SECRETSDIR/cloudflare_api_key
$SECRETSDIR
— это переменная окружения, содержащая путь к папке секретов Docker.
D. Используйте секреты в службах Docker
После глобального определения мы можем использовать секреты в сниппетах docker-compose для отдельных сервисов. Поскольку мы добавили данные учетной записи Cloudflare в качестве секретов Docker, давайте посмотрим, как их использовать во фрагменте кода docker-compose для Traefik.
Во-первых, мы должны сделать секреты доступными внутри контейнера Traefik. Для этого вам нужно добавить следующий блок в сниппет docker-compose для Traefik:
secrets:
- cloudflare_email
- cloudflare_api_key
Это делает секретный файл доступным в папке /run/secrets
внутри контейнера.
Затем мы можем установить переменные среды для чтения конфиденциальных данных из этих секретных файлов с помощью блока environment:
как показано ниже:
environment:
- CF_API_EMAIL_FILE=/run/secrets/cloudflare_email
- CF_API_KEY_FILE=/run/secrets/cloudflare_api_key
Обратите внимание, что к переменным окружения теперь добавляется _FILE в конце. Не пропустите это, иначе это не сработает.
Сохраните и заново создайте службу и проверьте журналы на наличие ошибок. Если контейнер не сможет правильно прочитать секреты, вы увидите это как ошибку в журналах.
Note
Чтобы секреты Docker работали правильно, базовый образ контейнера должен их поддерживать. Если образ имеет репутацию/надежный образ, очень высока вероятность того, что разработчики внедрили передовые методы обеспечения безопасности Docker , включая секреты Docker.
8. Используйте прокси-сервер Docker Socket
Каждый раз, когда вы предоставляете сокет Docker службе, вы упрощаете для контейнера получение root-доступа в хост-системе.
Но некоторым приложениям требуется доступ к сокету Docker и API (например, Traefik, Glances, Dozzle, Watchtower и т. д.).
Если Traefik будет скомпрометирован, ваша хост-система может быть скомпрометирована. Собственная документация Traefik перечисляет использование Socket Proxy в качестве решения.
Прокси-сервер сокета похож на брандмауэр для сокета/API докера. Вы можете разрешить или запретить доступ к определенному API.
Я начал с Socket Proxy от Tecnativa, но недавно перешел на Socket Proxy от FluenceLab, так как он обеспечивает более детальный контроль .
Добавьте сеть в свой файл compose (игнорируйте первую строку, если у вас уже есть блок network:):
networks:
socket_proxy:
name: socket_proxy
driver: bridge
ipam:
config:
- subnet: 192.168.91.0/24
И, наконец, вот фрагмент кода docker-compose для добавления прокси-сервера сокета для повышения безопасности докера:
# Docker Socket Proxy - Security Enchanced Proxy for Docker Socket
socket-proxy:
container_name: socket-proxy
image: tecnativa/docker-socket-proxy
restart: always
networks:
socket_proxy:
ipv4_address: 192.168.91.254 # You can specify a static IP
# privileged: true # true for VM. False for unprivileged LXC container.
ports:
- "127.0.0.1:2375:2375" # Port 2375 should only ever get exposed to the internal network. When possible use this line.
# I use the next line instead, as I want portainer to manage multiple docker endpoints within my home network.
# - "2375:2375"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- LOG_LEVEL=info # debug,info,notice,warning,err,crit,alert,emerg
## Variables match the URL prefix (i.e. AUTH blocks access to /auth/* parts of the API, etc.).
# 0 to revoke access.
# 1 to grant access.
## Granted by Default
- EVENTS=1
- PING=1
- VERSION=1
## Revoked by Default
# Security critical
- AUTH=0
- SECRETS=0
- POST=1 # Watchtower
# Not always needed
- BUILD=0
- COMMIT=0
- CONFIGS=0
- CONTAINERS=1 # Traefik, portainer, etc.
- DISTRIBUTION=0
- EXEC=0
- IMAGES=1 # Portainer
- INFO=1 # Portainer
- NETWORKS=1 # Portainer
- NODES=0
- PLUGINS=0
- SERVICES=1 # Portainer
- SESSION=0
- SWARM=0
- SYSTEM=0
- TASKS=1 # Portainer
- VOLUMES=1 # Portainer
Внимание
Никогда не открывайте порт 2375 для доступа в Интернет. Вас взломают. Это еще более важно для виртуальных частных серверов, которые обычно предоставляют доступ ко всем портам. Включите брандмауэр, чтобы разрешить только порты 80 и 443 (и заблокировать остальные) для прохождения на ваш сервер, а также реализовать обходной путь Docker IP Tables, описанный далее в этом руководстве.
Note
Кроме того, порт 2375
должен быть открыт только для внутренней сети (127.0.0.1:2375).
В блоке environment: указываем раздел Docker API, который хотим открыть или закрыть. Я добавил комментарии, чтобы описать, какие службы требуют каких разделов API. Например, если вы не используете WatchTower, вы можете ввести 0 для нескольких разделов API.
После запуска контейнера прокси-сервера Socket вы можете заменить прямой доступ к сокету Docker прокси-сервером Socket для всех служб, которые в нем нуждаются. Это можно сделать несколькими способами, в зависимости от того, как это поддерживает образ контейнера.
Для Traefik замените следующий аргумент CLI (если вы используете аргументы CLI вместо статических конфигураций):
- --providers.docker.endpoint=unix:///var/run/docker.sock
на
- --providers.docker.endpoint=tcp://socket-proxy:2375
Для других служб вы можете удалить указание Docker Socket в качестве тома (следующая строка под томами: ):
- /var/run/docker.sock:/var/run/docker.sock:ro
и добавьте переменную окружения DOCKER_HOST , как показано ниже:
DOCKER_HOST: tcp://socket-proxy:2375
Это то, что я делаю для Portainer и WatchTower.
Воссоздайте свой стек, и ваши службы должны использовать защищенный прокси-сервер сокета Docker вместо сокета Docker.
9. Измените DOCKER_OPTS на Respect IP Table Firewall
Случайно наткнулся на эту тему. Я включил UFW, как всегда делаю на своем VPS Digital Ocean, и заблокировал все, кроме 80 и 443. Я непреднамеренно попытался получить доступ к одной из служб, используя номер порта, и был шокирован тем, что я был подключен.
Покопавшись дальше, я наткнулся на этот открытый вопрос на GitHub . Почему это было открыто больше года, несмотря на огромное количество людей, запрашивающих исправление, мне не понятно.
Поэтому, если у вас включен прокси-сервер сокета и включен брандмауэр, из-за недостатка безопасности в докере хакеры все равно могут взломать вашу систему, используя порт прокси-сервера сокета (2375).
К счастью, есть обходной путь. В системах на базе Ubuntu/Debian отредактируйте /etc/default/docker и добавьте следующую строку:
DOCKER_OPTS="--iptables=false"
Сохраните файл и перезапустите службу Docker.
Попробуйте подтвердить исправление, обратившись к одной из ваших служб с помощью WAN-IP:PORT.
10. Контролируйте использование ресурсов Docker
Мне понравилось, что я могу устанавливать ресурсы для сервисов Docker. К сожалению, это возможно только с Docker-Compose версии 2 или режимом Docker Swarm.
Если вы используете любой из них, вы можете установить ограничения ресурсов для служб Docker .
Вот пример docker-compose для установки ограничений ресурсов в режиме Docker Swarm:
deploy:
resources:
limits:
cpus: '0.50'
memory: 50M
reservations:
cpus: '0.25'
memory: 20M
Установив ограничения ресурсов, вы можете ограничить любую службу, которая становится мошеннической и потребляет ваши системные ресурсы.
Защита приложений Docker с помощью Traefik
Есть вещи, которые можно сделать на стороне Traefik, чтобы защитить ваш стек от вредоносных атак. Давайте рассмотрим некоторые меры безопасности Traefik, которые можно реализовать.
11. Ограничение скорости
Ограничение скорости довольно распространено для смягчения атак методом грубой силы или отказа в обслуживании. В моем стеке Traefik Docker есть промежуточное ПО для определения ограничения скорости .
middlewares-rate-limit:
rateLimit:
average: 100
burst: 50
Приведенный выше общий набор чисел отлично работает для меня. Его можно настроить в соответствии с вашей ситуацией, используя документацию Traefik по ограничению скорости .
12. Заголовки безопасности Traefik
Заголовки безопасности — это основные требования к безопасности веб-сайта. Они защищают от различных атак, включая XSS, кликджекинг, внедрение кода и многое другое.
Вот заголовки безопасности Traefik, которые я определил как промежуточное ПО:
middlewares-secure-headers:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
hostsProxyHeaders:
- "X-Forwarded-Host"
sslRedirect: true
stsSeconds: 63072000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
# frameDeny: true #overwritten by customFrameOptionsValue
customFrameOptionsValue: "allow-from https:example.com" #CSP takes care of this but may be needed for organizr.
contentTypeNosniff: true
browserXssFilter: true
# sslForceHost: true # add sslHost to all of the services
# sslHost: "example.com"
referrerPolicy: "same-origin"
# Setting contentSecurityPolicy is more secure but it can break things. Proper auth will reduce the risk.
# the below line also breaks some apps due to 'none' - sonarr, radarr, etc.
# contentSecurityPolicy: "frame-ancestors '*.example.com:*';object-src 'none';script-src 'none';"
featurePolicy: "camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
customResponseHeaders:
X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex,"
server: ""
В Traefik была ошибка, из-за которой нельзя было определить заголовки безопасности как в динамической, так и в статической конфигурации. Это с тех пор было закрыто.
Так что теперь можно добавить sslForceHost и sslHost к отдельным службам, если хотите, для дополнительной безопасности.
13. Параметры TLS
Параметры TLS позволяют настраивать соединения TLS для защиты соединения между клиентом и вашей службой. Дополнительные пояснения можно найти в документации TLS от Traefik.
В моей настройке я определил следующие параметры TLS для Traefik:
tls:
options:
default:
minVersion: VersionTLS12
sniStrict: true
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
14. Многофакторная аутентификация
Это становится все более и более очевидным / обязательным. Если вы еще не защитили свои приложения Docker с помощью многофакторной аутентификации, сделайте это прямо сейчас. Я тестировал и использовал три системы аутентификации: Google OAuth, Authelia и Keycloak.
15. Защитите контейнеры Docker с помощью Cloudflare
Вот краткое изложение ключевых настроек Cloudflare для повышения безопасности контейнеров Docker при подключении к Интернету.
- Cloudflare Proxy — позволяет использовать улучшения безопасности и производительности Cloudflare.
- Режим SSL — полный или строгий. Это шифрует соединение между исходным сервером и Cloudflare и между Cloudflare и клиентом.
- Пограничные сертификаты:
- Всегда использовать HTTPS: ВКЛ.
- HTTP Strict Transport Security (HSTS): Включить (будьте осторожны)
- Минимальная версия TLS: 1.2
- Оппортунистическое шифрование: ВКЛ.
- TLS 1.3: ВКЛ.
- Автоматическая перезапись HTTPS: ВКЛ.
- Мониторинг прозрачности сертификата: ВКЛ.
- Правила брандмауэра. Создайте правила для разрешения или запрета определенного трафика (например, я разрешаю трафик только из РФ в мои частные приложения, так как я получаю к нему доступ только из РФ).
- Настройки брандмауэра:
- Уровень безопасности: Высокий
- Режим боя с ботом: ВКЛ.
- Прохождение испытания: 30 минут
- Проверка целостности браузера: ВКЛ.
Это настройки Cloudflare, связанные с безопасностью Docker.
Другие улучшения безопасности для стека Docker Traefik
Все вышеперечисленные рекомендации по безопасности докеров — это то, что я реализовал до сих пор. Но есть и другие, и я настоятельно рекомендую изучить следующее для дополнительной безопасности.
16. Fail2ban
Fail2ban сканирует ваши лог-файлы и блокирует IP-адреса, которые показывают злонамеренные намерения (например, поиск эксплойтов, неудачных паролей и т. д.). При обнаружении подозрительной активности он обновляет правила брандмауэра, чтобы заблокировать IP-адрес на указанный период времени.
17. Безопасность Docker Bench
Docker Bench for Security — это скрипт, который проверяет десятки распространенных передовых методов развертывания контейнеров Docker в рабочей среде .
18. RBAC
RBAC — это управление доступом на основе ролей. Если вы представляете предприятие или имеете несколько пользователей, это обязательно. Это может быть довольно дорого реализовать, но portainer делает это очень простым (поскольку кулинарная книга FunkyPenguin потрясающая … проверьте ее, если вы этого не сделали) за символическую плату.
19. Сканер уязвимостей контейнеров
Последним в списке лучших практик для безопасности докеров является сканер уязвимостей. Здесь есть несколько примеров, но я перечислю только один: Clair.
Clair — проект с открытым исходным кодом для статического анализа уязвимостей в контейнерах приложений.
Он использует Clair API для индексации образов контейнеров, а затем сопоставляет их с известными уязвимостями безопасности Docker.