Пошук уроків, статей та іншого контенту
Налаштуєте користувача контейнера без привілеїв root і зменшите наслідки компрометації застосунку.
За замовчуванням процес у контейнері часто запускається від імені root. Це означає, що застосунок має максимальні права всередині контейнера:
може змінювати файли, доступні root;
може встановлювати пакети або змінювати системні налаштування контейнера;
у разі вразливості наслідки компрометації будуть серйознішими.
Контейнер із користувачем без привілеїв root не робить застосунок автоматично безпечним, але зменшує кількість дій, які зможе виконати зловмисник після отримання контролю над процесом.
USERУ Dockerfile користувача процесів задають інструкцією USER:
USER appПісля цієї інструкції всі наступні команди та основний процес контейнера запускатимуться від імені app.
Користувача потрібно створити заздалегідь:
RUN addgroup -S app && adduser -S app -G app
USER appСинтаксис створення користувача залежить від базового образу. У прикладі вище використано Alpine Linux.
Створимо невеликий застосунок, який запускається без root.
DockerfileFROM alpine:3.20
# Створюємо групу та користувача без привілеїв root
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY app.sh .
# Передаємо файл користувачу app і робимо його виконуваним
RUN chown app:app /app/app.sh && chmod 755 /app/app.sh
# Усі наступні процеси запускатимуться від імені app
USER app
CMD ["./app.sh"]app.sh#!/bin/sh
echo "Застосунок запущено від користувача:"
id
echo "Застосунок може записати файл у /tmp" > /tmp/app-message.txt
echo "Файл створено успішно"Зберігайте обидва файли в одному каталозі. Зробіть образ і запустіть контейнер:
docker build -t non-root-demo .
docker run --rm non-root-demoПриблизний результат:
Застосунок запущено від користувача:
uid=100(app) gid=101(app) groups=101(app)
Файл створено успішноІдентифікатори можуть відрізнятися залежно від образу, але процес не повинен мати uid=0. Значення uid=0 означає root.
Перевірити користувача можна також окремою командою:
docker run --rm non-root-demo idДо USER app Dockerfile зазвичай виконує підготовчі операції від root:
встановлює системні пакети;
створює каталоги;
додає користувача;
копіює файли;
змінює власника файлів.
Після USER app процес уже не має прав root. Тому команди на кшталт apk add, apt-get install або запис у системні каталоги можуть завершитися помилкою.
Правильна загальна структура:
FROM alpine:3.20
# Підготовка образу від root
RUN addgroup -S app && adduser -S app -G app
RUN mkdir -p /app/data && chown -R app:app /app
COPY --chown=app:app . /app
WORKDIR /app
# Перехід до користувача без привілеїв
USER app
CMD ["./app.sh"]Користувач без root може працювати лише з файлами, до яких має доступ. Якщо застосунку потрібно записувати дані, каталог має належати цьому користувачу.
Наприклад:
RUN mkdir -p /app/data && chown -R app:app /app/dataАбо можна одразу змінити власника під час копіювання:
COPY --chown=app:app . /appНе варто вирішувати проблему доступу, надаючи всім користувачам повні права:
RUN chmod -R 777 /appТаке рішення послаблює захист. Краще надати власнику застосунку лише потрібні права.
Користувача можна задати не лише в Dockerfile, а й під час запуску контейнера за допомогою --user:
docker run --rm --user 1000:1000 alpine:3.20 idФормат:
--user UID:GIDУ цьому прикладі процес працює з ідентифікатором користувача 1000 і групи 1000.
Цей спосіб може бути корисним, коли один і той самий образ запускають у різних середовищах. Однак у користувача з таким числовим ідентифікатором усередині образу може не бути імені. Для більшості операцій важливі саме права та числові UID і GID.
Якщо користувача завжди має використовувати сам образ, надійніше вказати USER у Dockerfile.
Після запуску контейнера перевірте поточного користувача:
docker run --rm non-root-demo idТакож можна тимчасово запустити оболонку:
docker run --rm -it non-root-demo /bin/shУсередині контейнера виконайте:
idЯкщо вивід містить uid=0, процес працює від root. Для користувача без привілеїв значення uid має бути іншим.
USER вказано до підготовки файлівUSER app
RUN mkdir /app/dataКористувач app може не мати права створити каталог у потрібному місці. Створіть каталог і налаштуйте його права до USER app:
RUN mkdir -p /app/data && chown -R app:app /app/data
USER appКоманда COPY часто створює файли з власником root. Якщо застосунок має змінювати ці файли, використайте:
COPY --chown=app:app . /appабо:
RUN chown -R app:app /appКористувач без root зазвичай не може записувати в /, /usr, /etc та інші системні каталоги. Створіть окремий каталог даних і передайте його застосунку:
RUN mkdir -p /app/data && chown -R app:app /app/dataДеякі програми за замовчуванням намагаються:
відкрити привілейований порт;
змінити системні файли;
встановити пакети під час запуску;
створити файли в каталогах root.
Таку поведінку потрібно змінити в конфігурації застосунку або під час побудови образу. Не слід повертати root лише для того, щоб приховати проблему з правами.
Користувач USER app визначає, від імені кого працює процес усередині контейнера.
Це не те саме, що rootless-режим Docker, у якому сам Docker Engine або daemon працює без прав root. Ці налаштування вирішують різні завдання. У цьому уроці ми змінюємо користувача процесу контейнера за допомогою USER або --user.
Не запускайте прикладний процес від root без необхідності.
Створіть окремого користувача та групу в Dockerfile.
Використовуйте USER app до запуску основного процесу.
Налаштуйте власника файлів і каталогів до переходу на користувача без привілеїв.
Для одноразового перевизначення користувача застосовуйте docker run --user UID:GID.
Перевіряйте результат командою id.
Запуск без root зменшує наслідки компрометації, але не замінює інші заходи безпеки.