Перейти к содержанию


Салют 👋,
Данная лабораторная работа посвещена изучению 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, где прописаны версии зависимостей и инструкции, минимизирующие разрешения и атаки. Это инструкции, где описывается, как собрать образ. Впоследствии собирается контейнер.

Контейнер — это изолированная среда выполнения приложения с необходимыми зависимостями, кодом, системными утилитами, библиотеками и настройками. Исползует не собственну гостеву ОС, а ядро хостовой ОС и имеет своё собственное файловое пространство, процессы и сеть.

После сборки образа формируется контейнер, которые являются изолированными средами выполнения для достижения цели переносимости, воспроизведения.

Контейнеризация — это технология, позволяющая упаковать приложение вместе со всеми его зависимостями, библиотеками, настройками и средой выполнения в единый изолированный виртуальный контейнер.

  • Namespaces

Необходимы для организации изолированных рабочих пространств, - контейнеров. Когда мы запускаем контейнер, Docker создает набор пространств имен для данного контейнера, что создает изолированный уровень в своем простанстве имен и не имеет доступа к внешней системе. Пространство имен:

  • pid: для изоляции процесса
  • net: для управления сетевыми интерфейсами
  • ipc: для управления IPC ресурсами. (ICP: InterProccess Communication)
  • mnt: для управления точками монтирования
  • utc: для изолирования ядра и контроля генерации версий(UTC: Unix timesharing system)
  • Cgroups

Необходимы для контрольных групп в изоляции, где предоставляется приложению только те ресурсы, которые указываем. Позволяют разделять ресурсы железа и устанавливать пределы, ограничения.

$ 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 или с небезопасными настройками
    • присутствие секретов и конфиденциальных данных в образах
    • отсутствие регулярного обновления из-за неподдерживаемых образов
  • Контекст безопасности

    • Не задавать пользователей с правами «root» для работы сервисов внутри контейнеров. > Если для функционирования сервиса не требуются расширенные привилегии, то в Dockerfile необходимо явно прописать учетную запись пользователя с минимально необходимыми правами.
    • Не запускать контейнеры в привилегированном режиме. > Ключ «--privileged» отключает все средства изоляции (наложенные cgroup – контроллером устройства) docker-контейнера. Запуск контейнера с таким ключом обеспечит ему доступ к файловой системе и блочным устройствам (например, жесткому диску) хоста. Контейнеры должны быть запущены в непривилегированном режиме. Если контейнеру нужны дополнительные привилегии для корректной работы, то необходимо явно прописать или удалить требуемые docker capabilities.
    • Не отключать профили безопасности Docker. > По умолчанию для запуска контейнеров Docker использует профили безопасности Linux, лучше использовать профили AppArmor, SELinux, grsecurity, seccomp, - позволяют ограничить активности контейнера, обеспечивая контроль сети, использования дополнительных возможностей (docker capabilities), контроль обращений к файловой системе хоста и пр. Контейнеры должны работать с активными профилями безопасности Docker, не docker-default. Если необходимо использовать другой профиль, то это можно сделать с помощью --security-opt.
    • Не допускать запуск контейнеров, использующих тип сети «host» > В режиме Host контейнер использует ту же сеть, что и хост, т.е. контейнерная сеть не изолируется от сети Docker хоста и контейнер не получает собственный IP-адрес, что дает доступ к REST API daemon docker изнутри контейнера, а также к устройствам, расположенным в сети хоста. Для реализации сетевого взаимодействия между контейнерами, они должны запускаться в режиме bridge или none.
    • Не разрешать доступ к docker.socket изнутри контейнера. Не подключать docker socket в контейнер без необходимости, либо с использованием плагинов авторизации.
    • Не использовать секреты в открытом виде в Docker-файлах образов. По возможности не использовать переменные окружения и не хранить секреты внутри контейнера. Хранение и управление секретами возложить на сторонний сервис.
    • Ограничивать и контролировать использование ресурсов контейнерами. Указывать ограничения на уровне самого ПО или на уровне контейнеров для использования ресурсов хоста.
    • Контролировать качество базовых образов контейнеров. Использовать официальные образы и использовать образы с минимально необходимым набором инструментов.
    • Сканировать образы на наличие уязвимостей и проверки требований ИБ (Compliance Checks)
  • Дополнительно

В случае, если возникает проблема с вызовом docker buildx для macos silicon, следует использовать вот это описание из gistup для фикса samelink.


Задание

  • 1. Поставьте Docker и buildkit
$ brew install buildkit
$ brew install docker
  • 2. Перейдите в source и выведите на терминале, далее проанализируйте следующие команды консоли
$ docker buildx build -t hellow-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 и сделайте его анализ. Сделайте commit

  • 4. Замените в Dockerfileзначение скрипта на python тем, который вы сделали ранее в прошлых лабораторных работах. Вложите свой файл python в директорию. Сделайте анализ своего измененного 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"] 
  • 5. Выведите на терминале и проанализируйте следующие команды консоли. Сравните хеш сумму вашего архива с image.tar из репозитория, выведите на терминал.
$ docker buildx build -t hellow-appsec-world .
$ docker run hello-appsec-world
$ docker save -o hello_ypur_project.tar hello-appsec-world

$ docker load -i hello_ypur_project.tar
$ docker run hello-appsec-world

$ docker load -i image.tar
$ docker run hello-appsec-world
  • 6. Доработайте свой python скрипт подключаемыми библиотеками, далее их необходимо разместить в requirements.txt. Размещение библиотек в следующем формате:
flask==2.2.3
requests==2.28.1
  • 7. Сделайте commit. Повторите сборку приложения по вашему Dockerfile для доработанного скрипта python. Сохраните image в виде .tar архива. Сделайте commit.
  • 8. Выведите на терминале и проанализируйте следующие команды консоли
$ 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
  • 9. Выведите на терминале и проанализируйте в консоли процессы, которые запущены, владельцев по пользователям
 $ docker container run -it ubuntu /bin/bash
  • 10. Выведите оба контейнера first и second на терминал
  • 11. Перейдите в основной корень lab05 и выведите на терминале, и проанализируйте
$ docker-compose up --build
  • 12. Откройте соседнее окно терминала и и выведите на терминале
$ open -a "Google Chrome" http://localhost:8000
  • 13. Остановите работу docker-compose.
$ docker ps -a
$ docker ps -q
$ docker images

$ docker ps -q | xargs docker stop
$ docker-compose down
  • 14. Доработайте docker-compose и скрипт, который вы подготовили ранее, что бы вы смогли воспроизвести шаги п.11 по п.13 с демонстрацией. Сделайте commit.
  • 15. Залейте изменения в свой удаленный репозиторий, проверьте историю commit.
  • 16. Подготовьте отчет gist.

Copyright © 2025 Elijah S Shmakov

Logo


Логотип