Салют 👋,
Данная лабораторная работа посвящена изучению Docker и как с ним работать. Эта лабораторная работа послужит подпоркой для старта в выявлении и определении уязвимостей на уровне сканирования контейнеров при сборке приложений.
Для сдачи данной работы также будет требоваться ответить на дополнительные вопросы по описанным темам.
lab05
├── client
│ ├── client.py
│ ├── Dockerfile
│ └── requirements.txt
├── docker-compose.yml
├── README.md
├── server
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
└── source
├── Dockerfile
├── hello.py
├── image.tar
└── requirements.txtСборка приложения включает создание контейнерного образа, в котором упаковано приложение с конфигурациями, чтобы приложение функционировало. Docker основан на использовании общих функций ядра ОС Linux (cgroups, namespace) для изоляции и управления ресурсами.
Образ — это статический, неизменяемый шаблон, на базе которого создаются контейнера с ОС, приложением, зависимостями, библиотекакм и конфигурационными файлами. Нужен для создания воспроизводимой, неизменяемой среды выполнения приложений в контейнерах.
Для сборки образов используется Dockerfile, где прописаны версии зависимостей и инструкции, минимизирующие разрешения и атаки. Это инструкции, где описывается, как собрать образ. Впоследствии собирается контейнер.
Контейнер — это изолированная среда выполнения приложения с необходимыми зависимостями, кодом, системными утилитами, библиотеками и настройками. Использует не собственную гостевую ОС, а ядро хостовой ОС и имеет своё собственное файловое пространство, процессы и сеть.
После сборки образа формируется контейнер, которые являются изолированными средами выполнения для достижения цели переносимости, воспроизведения.
Контейнеризация — это технология, позволяющая упаковать приложение вместе со всеми его зависимостями, библиотеками, настройками и средой выполнения в единый изолированный виртуальный контейнер.
Необходимы для организации изолированных рабочих пространств — контейнеров. Когда мы запускаем контейнер, Docker создает набор пространств имен для данного контейнера, что создает изолированный уровень в своем пространстве имен и не имеет доступа к внешней системе.
Контрольные группы для изоляции ресурсов — предоставляют приложению только те ресурсы, которые указываем. Позволяют разделять ресурсы железа и устанавливать пределы, ограничения.
$ docker container run -d \
-e NGINX_HOST xxx.xxx \
-p 8080:80 \
-v "$PWD/html" usr/share/nginx/html \
--memory=50m \
--cpus="2.5" \
nginx- образ может содержать устаревшие или уязвимые версии библиотек CVE (Common Vulnerabilities and Exposures)
- поддельные и злонамеренные образы
- отсутствие подписей и проверки целостности
- ошибка конфигурации и избыток прав — образы с избыточными правами доступа, запуском от root или с небезопасными настройками
- присутствие секретов и конфиденциальных данных в образах
- отсутствие регулярного обновления из-за неподдерживаемых образов
В случае, если возникает проблема с вызовом docker buildx для macos silicon, следует использовать вот это описание из gistup для фикса samelink.
- 1. Поставьте
Dockerиbuildkit
# Ubuntu / Debian
$ sudo apt update && sudo apt install -y docker.io docker-compose
$ sudo systemctl enable --now docker
$ sudo usermod -aG docker $USER && newgrp docker
# Fedora
$ sudo dnf install -y docker docker-compose
$ sudo systemctl enable --now docker
$ sudo usermod -aG docker $USER
# macOS
$ brew install docker buildkit
# Проверка
$ docker --version
$ docker run hello-world- 2. Перейдите в
sourceи выведите на терминале, далее проанализируйте следующие команды консоли
$ docker buildx build -t hello-appsec-world .
$ docker run hello-appsec-world
$ docker run --rm -it hello-appsec-world
$ docker save -o hello.tar hello-appsec-world
$ docker load -i hello.tar
$ docker load -i image.tar-
3. Откройте
Dockerfileи проведите аудит безопасности по чеклисту:- Какой базовый образ используется? Он официальный? Есть ли пиннинг версии (тег, не
latest)? - Используется ли multi-stage build? Зачем?
- Есть ли инструкция
USER? От какого пользователя запускается приложение? - Используется
COPY . .или копируются только нужные файлы? - Есть ли
.dockerignore? Что он исключает? - Есть ли секреты или пароли в
ENV,ARGилиCOPY? - Пиннингованы ли версии зависимостей в
requirements.txt?
Зафиксируйте результат аудита в отчёте. Сделайте
commit. - Какой базовый образ используется? Он официальный? Есть ли пиннинг версии (тег, не
-
4. Создайте файл
.dockerignoreв директорииsource/со следующим содержимым:
.git
.gitignore
__pycache__
*.pyc
venv
.env
*.tar
*.md
Соберите образ до и после добавления .dockerignore, сравните размеры:
$ docker images | grep hello-appsec-worldОпишите в отчёте: какие файлы попадали в образ без .dockerignore и почему это опасно.
- 5. Замените в
Dockerfileскрипт на свойpython-файл из прошлых лабораторных работ. Вложите свой файл в директориюsource/. Проанализируйте и доработайтеDockerfileпод ваш скрипт. Сделайтеcommit.
Пример анализа по текущему
Dockerfileв репозитории
# Этап 1: сборка зависимостей
FROM python:3.11-slim AS builder
WORKDIR /hello
# Копируем файл с зависимостями
COPY requirements.txt .
# Устанавливаем зависимости в отдельную директорию wheelhouse для кеширования
RUN pip install --upgrade pip && pip wheel --wheel-dir=/wheels -r requirements.txt
# Этап 2: запускаемый образ
FROM python:3.11-slim
WORKDIR /hello
# Копируем файл с зависимостями
COPY --from=builder /wheels /wheels # Копируем собранные wheel-пакеты
COPY requirements.txt .
# Устанавливаем зависимости из wheel-пакетов
RUN pip install --no-index --find-links=/wheels -r requirements.txt
# Копируем исходный код приложения
COPY hello.py .
# Переменные окружения для улучшенной работы Python
ENV PYTHONUNBUFFERED=1
# Запускаем приложение
CMD ["python", "hello.py"] - 6. Выведите на терминале и проанализируйте следующие команды консоли. Сравните хеш сумму вашего архива с
image.tarиз репозитория, выведите на терминал.
$ docker buildx build -t hello-appsec-world .
$ docker run hello-appsec-world
$ docker save -o hello_your_project.tar hello-appsec-world
$ docker load -i hello_your_project.tar
$ docker run hello-appsec-world
$ docker load -i image.tar
$ docker run hello-appsec-world- 7. Доработайте свой
pythonскрипт подключаемыми библиотеками, далее их необходимо разместить вrequirements.txt. Размещение библиотек в следующем формате:
flask==2.2.3
requests==2.28.1
- 8. Сделайте
commit. Повторите сборку приложения по вашемуDockerfileдля доработанного скриптаpython. Сохранитеimageв виде .tarархива. Сделайтеcommit. - 9. Проанализируйте слои и размер образа. Сравните single-stage и multi-stage build:
# Посмотреть слои образа
$ docker history hello-appsec-world
# Размер образа
$ docker images hello-appsec-worldОпишите в отчёте: сколько слоёв, какой размер, какие слои самые тяжёлые. Если Dockerfile не использует multi-stage — переделайте на multi-stage и сравните размер до/после.
- 10. Проверьте, от какого пользователя работает контейнер:
$ docker run --rm hello-appsec-world whoami
$ docker run --rm hello-appsec-world idЕсли выводит root — добавьте в Dockerfile инструкцию USER с непривилегированным пользователем. Пересоберите и проверьте повторно. Сделайте commit.
- 11. Выведите на терминале и проанализируйте следующие команды консоли
$ docker login
$ docker tag hello-appsec-world yourusername/hello-appsec-world
$ docker push yourusername/hello-appsec-world
$ docker inspect yourusername/hello-appsec-world
$ docker container create --name first hello-appsec-world # выпишите id контейнера
$ docker image pull geminishkv/hello-appsec-world
$ docker inspect geminishkvdev/hello-appsec-world
$ docker container create --name second hello-appsec-world
- 12. Запустите контейнер Ubuntu и изучите изоляцию изнутри (связь с namespaces из материала):
$ docker container run -it --rm ubuntu /bin/bash
# Внутри контейнера:
$ whoami # от какого пользователя?
$ id # uid, gid
$ ps aux # какие процессы видны? (только свои — pid namespace)
$ cat /etc/os-release # какая ОС внутри?
$ hostname # имя хоста (uts namespace)
$ ls /proc/1/ns/ # namespace-файлы процесса PID 1
$ exitОпишите в отчёте: что показывает каждая команда и как это связано с namespaces (pid, uts, mnt).
- 13. Проверьте ресурсные лимиты контейнера — запустите с ограничением памяти:
# Запустить с лимитом 64 MB RAM
$ docker run -d --name stress-test --memory=64m --cpus=0.5 ubuntu sleep 300
# Проверить лимиты
$ docker stats stress-test --no-stream
# Почистить
$ docker rm -f stress-testОпишите в отчёте: что произойдёт, если приложение попробует выделить больше памяти, чем лимит? Зачем ограничивать ресурсы?
- 14. Выведите оба контейнера first и second на терминал
- 15. Создайте Docker-сеть и проверьте связность между контейнерами:
$ docker network create lab05-net
$ docker network ls
# Запустите два контейнера в одной сети
$ docker run -d --name net-a --network lab05-net nginx
$ docker run -it --rm --network lab05-net ubuntu bash -c "apt update && apt install -y iputils-ping && ping -c 3 net-a"
# Почистить
$ docker rm -f net-a
$ docker network rm lab05-netОпишите в отчёте: как контейнеры находят друг друга по имени? Какой DNS использует Docker?
- 16. Перейдите в основной корень
lab05и запустите docker compose:
$ docker compose up --build- 17. Откройте соседнее окно терминала и проверьте работу приложения
$ curl -i http://localhost:8000
# или откройте в браузере: http://localhost:8000- 18. Остановите docker compose и почистите ресурсы
$ docker ps -a
$ docker ps -q
$ docker images
$ docker ps -q | xargs docker stop
$ docker compose down- 19. Доработайте
docker-compose.ymlи скрипт из предыдущих шагов, чтобы воспроизвести шаги п.15–п.17 с демонстрацией. Сделайтеcommit. - 20. Залейте изменения в свой удалённый репозиторий, проверьте историю
commit. - 21. Подготовьте отчет
gist.
- Основы Docker — введение в контейнеризацию перед этой лабой
- Лаб. №6 — CIS Benchmark — аудит безопасности Docker
- CheatSheet: Docker — шпаргалка по командам
- CheatSheet: Dockerfile Security — безопасная сборка образов
- CheatSheet: .dockerignore — исключения при сборке
Если столкнулись с проблемами — смотрите Troubleshooting.