Docker можна тримати в продакшні місяцями без жодних видимих проблем. Контейнери запускаються, застосунки відповідають, нічого не ламається. А потім один відкритий порт або одне неправильно налаштоване дозволення дає зловмиснику точку входу, яку він навіть не мусив шукати. Більшість помилок у безпеці Docker не виглядають як помилки — доки щось не піде не так.
У цій статті розглядаються конкретні конфігурації, які створюють ризики для контейнерних середовищ, що кожна з них дає зловмиснику, а в кінці наведено чекліст, який можна перевірити на своєму стенді вже сьогодні.
Чому безпека Docker складніша, ніж здається
Контейнери здаються ізольованими. Ви запускаєте контейнер, він працює у власному просторі процесів, і зсередини сусідній контейнер наче не існує. Ізоляція є, але вона неповна. Контейнери спільно використовують ядро хоста, а це означає, що за певних умов процес усередині контейнера може отримати доступ до хост-системи повністю.
Docker за замовчуванням налаштований для зручності розробника, а не для захисту в продакшні. Root-доступ увімкнено. Усі порти можна прив'язати до будь-якого інтерфейсу. Моніторинг під час виконання відсутній. Більшість розробників залишають ці налаштування, випускають контейнер і рухаються далі. Для старту — цілком прийнятно; як завершена позиція безпеки — ні.
Відповідно до Звіт Red Hat «2024 State of Kubernetes Security», 67% організацій затримали або сповільнили розгортання застосунків через проблеми з безпекою контейнерів або Kubernetes. Це тертя зазвичай виникає не через атаки. Воно виникає тоді, коли команди виявляють, що їхні контейнерні конфігурації потребують захисту, якого спочатку не передбачали.
Ми нерідко бачимо, як контейнери в продакшні працюють з тією самою конфігурацією, що й на локальній машині розробника. Саме там помилки безпеки Docker поступово накопичуються непомітно — без жодних симптомів, доки не відбудеться аудит або збій.
Помилки, що створюють ці прогалини, конкретні, передбачувані й здебільшого усувні — і починаються вони на рівні конфігурації.
Типові помилки конфігурації Docker
Більшість зломів контейнерів починається не з експлойту нульового дня. Вони починаються з конфігурації, встановленої в перший день без особливих роздумів про мережеву доступність або межі привілеїв.
Стандартні налаштування Docker розраховані на те, щоб просто працювати. Різниця між «функціонує» і «захищено» — саме там накопичуються ризики безпеки контейнерів Docker, особливо в self-hosted-розгортаннях, які запустили і більше не чіпали.
Ми часто бачимо таку картину: контейнери на серверах з публічним IP з прив'язками портів, налаштуваннями користувачів і мережевими конфігураціями точно такими, якими вони були під час першого розгортання.
Запуск контейнерів від імені root
Якщо запустити контейнер Docker без вказівки користувача, він працюватиме від імені root. Це означає, що будь-який процес усередині контейнера, включно з вашим застосунком, матиме root-рівень привілеїв у просторі імен контейнера.

Root усередині контейнера — це не те саме, що root на хості, але розмежування не є абсолютним. Експлойти підвищення привілеїв, що атакують середовище виконання, — як-от добре задокументований runc CVE-2019-5736 та подібні вразливості — здебільшого вимагають root-процесу в контейнері для успішного виконання.
Контейнери без root-процесу усувають саму умову, яку використовують такі атаки, суттєво звужуючи поверхню атак для цього класу вразливостей, хоча й не виключають ризик виходу з контейнера повністю.
Це вирішується додаванням директиви USER до вашого Dockerfile. Деякі офіційні образи постачаються з непривілейованим користувачем, якого можна активувати директивою USER, але багато з них досі використовують root за замовчуванням без готового користувача для застосунку. У таких випадках потрібно створити користувача в Dockerfile перед перемиканням на нього. Для більшості self-hosted налаштувань ця одна зміна усуває цілу категорію ризиків підвищення привілеїв.
Надмірне відкриття портів у публічний інтернет
Коли ви публікуєте порт через Docker, Docker безпосередньо записує власні правила iptables. Ці правила спрацьовують до правил брандмауера на рівні хоста. Це відома поведінка, про яку повідомляє спільнота та задокументована в посібнику Docker з фільтрації пакетів, а не помилка налаштування, і це означає, що UFW та подібні інструменти не блокують те, що Docker вже відкрив.

Docker записує правила безпосередньо до iptables, оминаючи UFW та firewalld на багатьох хостах Linux. Це означає, що порт, прив'язаний до 0.0.0.0, може бути публічно доступний навіть якщо ваш брандмауер виглядає налаштованим. Cloud security groups та правила ланцюжка DOCKER-USER можуть блокувати цей трафік, тому реальний рівень відкритості залежить від вашого конкретного мережевого налаштування.
Де можливо, прив'язуйте сервіси до 127.0.0.1, направляйте публічний трафік через reverse proxy та публікуйте лише те, що справді потребує зовнішнього доступу. Reverse proxy — найнадійніший спосіб контролювати, що доступне ззовні хоста.
Ігнорування мережевої ізоляції між контейнерами
Будь-який контейнер у цій мережі може звертатися до будь-якого іншого без обмежень. Мостова мережа за замовчуванням не фільтрує трафік між контейнерами, що її використовують, і більшість налаштувань цю конфігурацію ніколи не змінюють.

Якщо один контейнер скомпрометовано, відкрита комунікація стає шляхом для бокового переміщення. Frontend-контейнер може звернутися до бази даних, внутрішнього API або будь-чого іншого в тій самій мостовій мережі за замовчуванням, навіть якщо такий доступ ніколи не був передбачений.
Мережі, визначені користувачем, дають явний контроль над тим, які контейнери можуть спілкуватися між собою, але одна спільна мережа для всіх сервісів все одно дозволяє вільний трафік між контейнерами. Реальна ізоляція вимагає розміщення сервісів, які не повинні взаємодіяти, у різних мережах. Відключення мостової мережі за замовчуванням — це відправна точка, а не кінцева мета.
Недооцінка сокета Docker
Сокет Docker за шляхом /var/run/docker.sock є інтерфейсом керування всім рушієм Docker. Монтування його в контейнер дає цьому контейнеру прямий API-доступ до демона, що працює на хості.

Маючи такий доступ, контейнер може запускати нові контейнери, монтувати директорії хоста, перевіряти та змінювати запущені контейнери і фактично керувати хост-машиною. Поверхня атаки еквівалентна root-доступу на хості, тому будь-який інструмент, що вимагає доступу до сокета, заслуговує на ретельну оцінку.
Для більшості задач існують безпечніші альтернативи: обмежені API або інструменти керування Docker що не потребують доступу до сокета. Docker всередині Docker має власні компроміси щодо безпеки та операційних аспектів і не є простою заміною.
Помилки в конфігурації створюють початкову вразливість. Вибір образів і залежностей визначає, наскільки ця вразливість накопичується з часом.
Помилки в образах і секретах, що переживають контейнер
Коли ви зупиняєте контейнер, помилки конфігурації всередині нього також зупиняються. Коли ви перезбираєте образ, що містить вразливість або жорстко закодовані облікові дані, проблема повертається разом із контейнером. Помилки на рівні образу не скидаються між деплоями.
Вони переміщуються разом із образом у кожне середовище, яке його завантажує, кожен реєстр, що його зберігає, і до кожного члена команди, який його запускає. Ця стійкість робить управління образами та секретами окремою категорією ризику, яку варто перевіряти незалежно від конфігурації.
Ми часто бачимо таку закономірність: образ, ретельно підібраний на початку проєкту і жодного разу не перезібраний відтоді, поступово відходить від вихідного рівня безпеки, який він представляв спочатку.
Використання ненадійних або застарілих образів
Публічні реєстри відкриті для всіх. Шкідливі образи поширювалися через Docker Hub із криптомайнерами та бекдорами, вбудованими в історію шарів, які зберігаються після перезапуску контейнера. Перевірка перед завантаженням важлива, особливо для образів від неофіційних або невідомих видавців.

Окрема проблема — застарілість. Офіційний образ, завантажений шість місяців тому і жодного разу не перезібраний, накопичує невиправлені вразливості Docker з кожним новим CVE, опублікованим проти його пакетів. Образ не зламаний. Він просто вже не актуальний.
Звіт Sonatype «2024 State of the Software Supply Chain» показав, що в 95% випадків, коли використовується вразливий компонент, виправлена версія вже доступна, а 80% залежностей застосунків залишаються без оновлень понад рік. Ця закономірність стосується і базових образів Docker, оскільки вони спираються на ті самі пакети з відкритим кодом.
Використовуйте офіційні образи від перевірених видавців і фіксуйте конкретні теги версій замість "latest". Налаштуйте регулярне перезбирання, щоб образи залишалися актуальними.
Хардкодування секретів у Dockerfile та Compose-файлах
Облікові дані, записані в інструкцію ENV або ARG у Dockerfile, захардкоджені в блоці environment у Compose-файлі, передані як аргументи збірки або збережені у файлі .env, закомітованому до системи контролю версій, не зникають після зупинки контейнера. Вони залишаються в історії шарів образу або в репозиторії та доступні кожному, хто може до них дістатися.

Це одна з найбільш недооцінених помилок безпеки в Docker, бо в процесі розробки вона не проявляється. Ключ API в інструкції ENV працює коректно. Але він також є у вашому репозиторії, запечений в образ і поширюється скрізь, куди цей образ потрапляє.
Сучасний Docker Compose підтримує вбудований механізм секретів, який монтує облікові дані під час виконання, не запікаючи їх в образ. Секрети API у Docker і зовнішні менеджери секретів дотримуються того самого принципу. Ці підходи повністю виключають облікові дані з артефактів збірки та закомічених файлів.
Змінні середовища під час виконання — це краще рішення, ніж захардкоджені облікові дані, але вони все одно доступні через вивід Docker inspect, логи та дампи аварійних завершень. Це крок уперед порівняно з запеченими секретами, але не остаточне рішення.
Нерегулярне оновлення образів контейнерів
Тривала робота на одному образі — поширена звичка. З кожним днем після публікації нової вразливості, до якого ви не перезібрали образ, ваші контейнери несуть вікно ризику, яке зростає без жодних видимих змін.
Дотримуйтеся стабільного графіка перезбирання. Там, де можливо, автоматизуйте цей процес і регулярно запускайте сканер вразливостей для поточних образів. Мета — не досконалість, а скорочення часу між виходом патча та його розгортанням.
У швидких деплоях контроль доступу та моніторинг часто відходять на другий план. Саме в цих категоріях інциденти найдовше залишаються непоміченими.
Прогалини в контролі доступу та видимості
Коли контейнер запущено з надійною конфігурацією та актуальними образами, залишаються два типи збоїв. Обидва непомітні за своєю природою: слабкий контроль доступу не дасть про себе знати, поки ним хтось не скористається, а прогалина в моніторингу — поки ви не спробуєте розслідувати активність, яку ніхто не логував.
Те саме Дослідження Red Hat за 2024 рік виявило, що у 42% команд бракує достатніх можливостей для боротьби з загрозами безпеці контейнерів.
Як правило, прогалини в моніторингу виявляються під час розслідування інцидентів, а не до них. До того часу, коли видимість стає пріоритетом, зазвичай уже доводиться реагувати на те, що сталося, а не запобігати цьому.
Слабка автентифікація та відкриті панелі керування
Дашборд керування контейнерами на публічній IP-адресі без автентифікації не потребує досвідченого зловмисника. Достатньо знати адресу. Це значно нижча планка, ніж більшість команд усвідомлює.

Інструменти моніторингу та керування на власному хостингу зазвичай постачаються з вебінтерфейсом, доступним на всіх мережевих інтерфейсах. Залишати їх на публічній IP-адресі без автентифікації — це те саме, що залишити адмін-панель відчиненою навстіж.
Автентифікація, зворотний проксі та розміщення у приватній мережі — це базовий мінімум. Контроль доступу — це крок конфігурації, який ви додаєте до будь-якого інтерфейсу керування; він не увімкнений за замовчуванням.
Той самий принцип стосується Docker CLI та GUI керування; доступ на рівні адміністратора до демона несе однаковий ризик незалежно від інтерфейсу.
Відсутність моніторингу активності контейнерів
Якщо контейнер скомпрометовано, активність зловмисника залишає сліди: зміни в поведінці процесів, незвичні мережеві з'єднання, несподівані модифікації файлів. Без збору логів ці сліди не існують у формі, придатній для аналізу.
Централізований збір логів, журналювання аудиту контейнерів та інструменти моніторингу в реальному часі дають вам дані для виявлення аномальної активності до того, як ситуація погіршиться. Мета не в тому, щоб аналізувати кожен рядок. Мета — мати дані під рукою, коли потрібно провести розслідування.
Контейнерні середовища, які мовчки працюють у продакшені без конвеєра логів і без сповіщень, — це не низькообслуговувані рішення. Це непідконтрольні рішення. Це два різні операційні стани.
Чому середовище інфраструктури також має значення
Безпека контейнерів починається з конфігурації, але конфігурація працює поверх інфраструктури. Хост із некоректно налаштованою мережею, спільними ресурсами або без фільтрації на мережевому рівні створює умови, які впливають на кожен контейнер над ним. Правильно налаштувати контейнери і правильно налаштувати сервер — це два окремі завдання.
Багато прогалин у безпеці Docker посилюються умовами, які контейнери успадковують від середовища:
- Сервер зі спільною оренда без апаратної ізоляції між орендарями
- Хост-ядро без встановлених патчів
- Хост без вбудованої фільтрації на мережевому рівні
Це не скасовує необхідності виконання кроків конфігурації, описаних вище, — належне зміцнення контейнерів важливе незалежно від рівня інфраструктури. Старт на ізольованій інфраструктурі усуває один рівень проблем із рівняння.
У Cloudzy ми пропонуємо два варіанти залежно від потреб вашого середовища:
- Linux VPS: чисте середовище для самостійного розгортання Docker та застосування кроків зміцнення з цієї статті
- Portainer VPS: варіант в один клік із попередньо встановленим Portainer; сервер завантажується, і ви вже в дашборді
Обидва варіанти працюють на однаковій інфраструктурі: віртуалізація KVM, процесори AMD Ryzen 9 CPU з тактовою частотою до 5.7 GHz у режимі boost, пам'ять DDR5, сховище NVMe SSD, мережа до 40 Gbps і безкоштовний захист DDoS через фільтрацію BuyVM — у 12 локаціях по всьому світу з гарантією доступності 99.95% (SLA).
Детальніше про запуск Portainer на VPS ми розповідаємо в окремій статті.
Практичний чеклист безпеки для розгортань Docker
Більшість помилок безпеки Docker, описаних вище, виникають через одиничні рішення конфігурації, прийняті одного разу і ніколи не переглянуті. Перевірка наявного середовища за цим чеклистом виявляє такі прогалини. Він працює як інструмент аудиту, а не як інструкція з розгортання.
Ці найкращі практики безпеки Docker охоплюють захист контейнерів Docker від найпоширеніших помилок конфігурації, описаних вище.
Короткий довідник: усі 9 помилок
| Помилка | Категорія | Швидке виправлення |
| Запуск з правами адміністратора | Конфігурація | Додати USER директива до вашого файлу Docker |
| Порти прив'язані до 0.0.0.0 | Конфігурація | Прив'яжіться до 127.0.0.1 і направляйте трафік через зворотний проксі |
| Без ізоляції мережі | Конфігурація | Розподіліть сервіси по окремих мережах з користувацьким визначенням, виходячи з потреб доступу. |
| Примонтований сокет Docker | Конфігурація | Видаліть монтування; використовуйте обмежені API або альтернативи |
| Ненадійні або застарілі образи | Зображення | Використовуйте офіційні образи з фіксованими тегами версій |
| Жорстко закодовані секрети | Зображення | Перенесіть облікові дані до змінних середовища або менеджера секретів |
| Відсутній розклад перезбірки образів | Зображення | Встановіть щомісячний цикл перезбірки; автоматизуйте там, де можливо |
| Неавтентифіковані панелі керування | Доступ | Додайте автентифікацію і перемістіть інтерфейси керування в приватні мережі |
| Відсутній збір журналів контейнерів | Доступ | Налаштуйте централізоване логування і моніторинг середовища виконання |
Рекомендуємо спочатку запустити перевірку на наявних налаштуваннях, оскільки саме там прогалини найімовірніше вже є.
Контейнери запущені не від root: Перевірте ваші файли Docker на наявність директиви USER. Якщо її немає, контейнер запускається від root.
Прив'язка портів обмежена до localhost або через проксі: Запустіть docker ps і перевірте прив'язки портів. Запис 0.0.0.0:PORT може бути публічно доступним на хостах, де його не блокує жодна група безпеки вище за рівнем, зовнішній фаєрвол або правило ланцюжка DOCKER-USER.
Використовуються користувацькі bridge-мережі: Контейнери в стандартній bridge-мережі Docker можуть вільно звертатися один до одного. Контейнери в одній користувацькій bridge-мережі також можуть спілкуватися між собою, тому розподіляйте сервіси по окремих мережах відповідно до меж довіри для реальної ізоляції.
Сокет Docker не примонтований у контейнерах: Перевірте файли Compose і аргументи запуску. Якщо /var/run/docker.sock вказано як том, переконайтеся, що це необхідно і зроблено свідомо.
Базові образи від перевірених видавців із зафіксованими версіями: FROM ubuntu:latest завантажує невизначену, потенційно застарілу версію. Зафіксуйте конкретний реліз.
Жодних секретів у Docker-файлах, Compose-файлах або аргументах збірки: Історія шарів образу зберігає облікові дані навіть після видалення контейнера. Використовуйте Compose secrets, Swarm secrets, секретні монтування під час збірки або зовнішній менеджер секретів. Змінні середовища під час виконання кращі за захардкоджені значення, але все одно відображаються у виводі inspect та логах.
Розклад перезбірки образів визначено: Старі образи накопичують вразливості. Щомісячна перезбірка дозволяє тримати вікно ризику в прийнятних межах для більшості конфігурацій.
Інтерфейси керування захищені автентифікацією: Будь-яка панель керування на публічній IP-адресі без автентифікації - це відкрита точка входу. Де можливо, розміщуйте такі інтерфейси в приватній мережі.
Логи контейнерів збираються: Без конвеєра збору логів виявлення інцидентів залежить від видимого впливу на систему. Це запізніла ознака для реагування.
Висновок
Стандартна конфігурація Docker орієнтована на зручність, а не на безпеку. Більшість помилок, розглянутих у цій статті, пов'язані з налаштуваннями, які так і не були змінені після першого розгортання, а не зі складними атаками.
Виправлення здебільшого є одноразовими рішеннями щодо конфігурації: директива USER, зміна прив'язки порту, окрема мережа, розклад перезбірки. Для більшості конфігурацій жодне з них не потребує нових інструментів.
Правильна конфігурація контейнера - це перше завдання. Інфраструктура, на якій він працює, - друге. Обидва аспекти важливі, і жоден не замінює інший.