Содержание статьи
В такой ситуации можно начать с мониторинга информационной безопасности происходящего в контейнерах, а для этого понадобится собирать события безопасности, то есть, проще говоря, логи. И здесь нас ждет ряд побочных эффектов, возникающих из‑за эфемерной сути контейнеров Docker. В этой статье поговорим как раз об этих проблемах и вариантах их решения.
Логирование в Docker
Уровни ведения журналов
Сначала нужно понять, как в Docker реализовано журналирование событий. Существует два уровня ведения журналов:
- журналы демона Docker;
- журналы контейнерных приложений.
Демон Docker записывает свои журналы в /
(в дистрибутивах на основе Debian) или /
(в дистрах, совместимых с Red Hat).
В журналах демона можно найти информацию о функционировании Docker на уровне платформы контейнеризации, включая события жизненного цикла контейнера, настройки сети, входящие API-запросы и многое другое.
Сюда же входят и все журналы, которые относятся к конкретному контейнерному приложению. По умолчанию при ведении журнала в формате JSON путь к журналам контейнера будет следующим:
/var/lib/docker/containers/<container_id>/<container_id>-json.log
При создании нового контейнера ему присваивается уникальный ID. На хосте, в каталоге /
, создается директория с тем же ID в качестве названия, а внутри — сам файл журнала, название которого тоже состоит из префикса json
и ID контейнера. При удалении контейнера файл журнала удаляется вместе с ним.
Эти особенности выливаются в настоящие проблемы для команд информационной безопасности, поскольку мешают собирать события. Ведь каждый контейнер по умолчанию записывает события в свой отдельный журнал, журналов получается много, а путь к журналу конкретного контейнера зависит от его ID, который присваивается при создании контейнера и сбрасывается при удалении контейнера, то есть путь к журналу может быть разным.
Помимо ведения журнала в формате JSON, Docker поддерживает и другие методы мониторинга. За каждый из методов отвечает драйвер ведения журнала. Давай посмотрим, какими они бывают.
Драйверы ведения журналов
Драйверы журналов определяют, как журналы собираются, обрабатываются и хранятся для каждого контейнера.
Контейнер отправляет события на стандартный поток вывода STDOUT
и поток ошибок STDERR
. Далее драйвер ведения журнала считывает эти события, обрабатывает их и, например, если это драйвер json-file, сохраняет их файл локально на хосте. Если же используется другой драйвер, например Syslog, данные отправляются в указанную точку назначения по протоколу TCP/UDP. Схема с примерами информационных потоков — ниже.
Драйвер ведения журнала и его параметры можно определить как на уровне демона Docker в конфиге daemon.
(параметры будут распространяться на все вновь созданные контейнеры), так и на уровне конкретного контейнера при его запуске, использовав docker
или утилиту docker
.
Режимы доставки журналов
Режим доставки журналов в Docker определяет, как журналы передаются из работающих контейнеров в драйвер. Существует два режима такой доставки: блокирующий и неблокирующий.
В блокирующем режиме приложение отправляет события непосредственно драйверу и может прерывать работу приложения, если доставка не завершена. Другими словами, если драйвер не может справиться с объемом записываемых событий, то демон блокирует отправку событий из контейнера, что может вызвать задержки в работе самого приложения. Но этот режим гарантирует отправку всех событий без потерь.
Блокирующий режим включен по умолчанию для драйверов, которые записывают события непосредственно в журнал на локальном хосте. Например, json-file и journald.
В неблокирующем режиме события сначала записываются в кольцевой буфер в памяти, из которого драйвер уже считывает события. Размер буфера фиксированный. Если драйвер недоступен, Docker не будет приостанавливать работу приложения и продолжит наполнение буфера. Но если буфер журнала будет переполнен, это приведет к потере событий. Чтобы этого избежать, можно увеличить максимальный размер буфера с одного мегабайта (по умолчанию) до более подходящего размера с помощью параметра max-buffer-size
.
Неблокирующий режим используется, когда драйвер должен установить соединение с удаленным сервером для отправки событий (например, Syslog, Fluentd и тому подобные решения).
Режимы доставки можно определить как на уровне демона Docker, так и на уровне конкретного контейнера.
Разобравшись с основами журналирования в Docker, давай подробнее разберем проблематику сбора событий.
Проблематика
Сбор событий со всех контейнеров
Если стоит задача собрать события со всех контейнеров Docker, то в случае с умолчательным драйвером json-file это можно сделать средствами Rsyslog. Это стандартный метод пересылать события в системы класса Log management или Security information and event management (LM/SIEM).
Пример файла с настройками:
module(
load="imfile" PollingInterval="10")
input(type="imfile" File="/var/lib/docker/containers/*/*-json.log"
Tag="docker"
Severity="Info"
Facility="local7")
local7.* @<ip-адрес коллектора LM/SIEM-системы>:<порт>
С помощью маски */
можно указать путь к журналам всех контейнеров, развернутых на хосте. Но в итоге на стороне LM/SIEM-системы получим общий поток событий, в котором не сможем отличить, с какого контейнера получено то или иное событие. А для локализации ИБ‑инцидента это крайне важно, особенно если контейнеров несколько десятков или даже сотен.
Ниже — примеры двух событий, полученных из разных контейнеров, но, с каких именно контейнеров они пришли, определить сложно:
<190>Apr 5 09:25:01 srv-01 docker { "log":"2024-04-05 06:25:01.123 UTC [72]FATAL: password authentication failed for user "admin"\r\n", "stream":"stdout", "time":"2024-04-05T06:25:01.124670483Z"}<190>Apr 5 09:32:53 srv-01 docker { "log":"::ffff:10.10.10.1 - - [05/Apr/2024:06:32:53 +0000] "POST /authenticate/login HTTP/1.1" 302 199 "http://10.10.10.170:5051/login?next=%2Fbrowser%2F" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"\n", "stream":"stdout", "time":"2024-04-05T06:32:53.985501905Z"}
Какие тут могут быть варианты решения проблемы?
Решение 1
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»