Добрый день! Сегодня мы поговорим о контейнеризации, а именно о наиболее популярной на данный момент технологии её реализации - Docker. Также вашему вниманию будут представлены уязвимости при реализации данной технологии.

Актуальность

Наблюдая за развитием крупных компаний не трудно заметить нарастающие темпы перехода от виртуализации к контейнеризации. Эти изменения обусловлены тем, что актуальная на данный момент технология контейнеризации позволяет экономить на железе, она менее ресурсозатратная, в отличие от своего конкурента, пока что оставим вопрос различия этих технологий открытым и перейдём к нему позже. Также рассматривая эту технологию в контексте информационной безопасности можно сказать, что контейнеризация повышает безопасность приложений, поскольку каждый контейнер работает в изолированной среде, что снижает риск атаки на другие приложения или систему хоста.

Главное что нужно знать о Docker

Прежде чем начать разговор о докере следует узнать основные принципы контейнеризации.
Термин описывающий данную технологию даёт возможность достаточно полно понять её смысл. Начнём с рассмотрения на абстрактных примерах для более простого понимания. Я думаю каждый из нас знает что такое контейнер для морских перевозок и баржа, которая занимается их транспортировкой. Представим что в каждом из контейнеров мы создаем свою экосистему, в одном мы симулируем Северный полюс с соответствующей флорой и фауной, в другом тропики и так до бесконечности. Затем мы размещаем их на барже, казалось бы разный климат может навредить соседним контейнерам, но так как они являются абсолютно изолированными никаких угроз не возникает как для соседей, так и для баржи.
Переходя к нашей теме можно провести следующую аналогию. В каждом контейнере запущена своя ОС с соответствующими приложениями, в нем настроены все зависимости необходимые для полноценного функционирования программ и сервисов, в каждом из контейнеров могут находится абсолютно несовместимые системы как для взаимодействия между собой, так и с хостовой системой, но никаких конфликтов, конечно же при правильной настройке, возникать не будет за счёт изоляции этих систем.

Теперь поговорим непосредственно про Docker. Сама по себе технология контейнеризации зародилась достаточно давно, но именно после представления своего продукта компанией Docker Inc., а это 2014 год, начался бурный рост и повсеместное внедрение.

Почему именно Docker:

  • Откат до предыдущей версии. В любой момент можно вернуться к исходному состоянию контейнера, что упрощает тестирование и исправление ошибок. Также можно перезагрузить контейнер, что иногда помогает решить проблему.

  • Готовый набор для запуска. Контейнер включает в себя всё необходимое для работы приложения, включая среду выполнения. Таким образом, можно написать приложение в этой среде и быть уверенным, что оно будет работать корректно после запуска на любом сервере. Место и способ написания кода не влияют на его работоспособность при использовании контейнера.

  • Малый размер. В отличие от виртуальных машин, контейнеры занимают значительно меньше места и быстрее запускаются. Их размер обычно составляет всего несколько сотен мегабайт.

  • Защищённость. У контейнера нет доступа к данным на хосте, что повышает безопасность работы приложения.

  • Простота управления. Docker-образы хранятся в реестре, откуда их можно быстро запустить. С помощью Docker можно управлять контейнерами: запускать, сохранять, редактировать, перезагружать. Если контейнеров много, используются инструменты для массового управления — оркестраторы. Стандартный инструмент для Docker-контейнеров — Kubernetes. Говоря о Docker невозможно хотя бы вскользь, но не задеть тему Kubernetes. Kubernetes — это инструмент, который позволяет автоматизировать развёртывание, масштабирование и управление контейнерными приложениями. Он предоставляет механизмы для управления кластером хостов, на которых работают контейнеры, и позволяет группировать контейнеры в управляемые службы, которые можно легко масштабировать. Kubernetes также предоставляет механизмы для управления жизненным циклом контейнеров, включая автоматическое масштабирование, автоматический перезапуск и управление ресурсами.

Отличие от виртуальных машин

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

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

  2. Масштабируемость: Виртуальные машины могут быть масштабированы вертикально (увеличение ресурсов одной виртуальной машины) или горизонтально (создание новых виртуальных машин), но это требует дополнительных затрат на ресурсы. Контейнеры могут быть легко масштабированы горизонтально, так как они используют общие ресурсы и могут быть запущены на одном хосте.

  3. Управление: Виртуальные машины имеют своё собственное управление и требуют отдельных инструментов для управления каждым экземпляром. Контейнеры используют общий менеджер контейнеров, который управляет всеми контейнерами на хосте. В целом, выбор между виртуальными машинами и контейнерами зависит от конкретных потребностей вашего проекта. Если вам нужна быстрая и масштабируемая система для запуска множества приложений, то контейнеры будут лучшим выбором.

Основы создания Docker

Самое время перейти к практической части нашего материала, но и тут не всё так просто. Чтобы знать как пользоваться докером, тем более создавать его следует усвоить из каких основных компонентов он состоит.
Экосистема Docker состоит из двух типов компонентов:

  • системных.

  • переменных. Системные компоненты включают в себя Docker host (сервер Docker), Docker daemon (демон Docker), Docker client (клиент Docker) и Docker-compose (менеджер запуска кластера контейнеров). Docker host - это просто компьютер или виртуальный сервер, на котором установлен Docker. Docker daemon - это центральный системный компонент, который управляет всеми процессами Docker: создание образов, запуск и остановка контейнеров, скачивание образов. Docker client - это утилита, предоставляющая API к демону Docker.

Основные переменные компоненты включают в себя: Dockerfile (файл Docker), Docker image (образ Docker), Docker container (контейнер Docker).
Теперь разберемся подробно с переменными компонентами.

Начнем пожалуй с Dockerfile. Dockerfile - это текстовый файл, который содержит инструкции для сборки образа Docker. Этот файл используется для определения того, как будет построен образ Docker, включая установку зависимостей, настройку среды выполнения, копирование файлов и многое другое.
Файл Dockerfile состоит из серии инструкций, которые выполняются в определенном порядке. Некоторые из наиболее распространенных инструкций включают FROM (используется для указания базового образа), RUN (для выполнения команд в контейнере), COPY (для копирования файлов в контейнер), EXPOSE (для указания портов, которые должны быть открыты для внешнего доступа) и ENTRYPOINT/CMD (для определения команды, которая будет запущена при старте контейнера).
При создании нового образа Docker, Dockerfile используется для создания нового контейнера на основе базового образа, который затем может быть дополнительно настроен и оптимизирован для конкретного приложения или задачи. После создания образа Docker, он может быть сохранен в репозитории Docker Hub или другом частном репозитории для последующего использования.
Пример DockerFile

FROM python:3.7.2-alpine3.8
RUN apk update && apk upgrade
COPY . ./app
RUN ["mkdir", "/a_directory"]
CMD ["python", "./my_script.py"]

Docker image
Docker image, или образ Docker, представляет собой файл, который содержит всю необходимую информацию для создания контейнера. Этот файл является основным строительным блоком Docker и содержит метаданные, такие как имя, версию, зависимые пакеты и команды, необходимые для запуска приложения внутри контейнера.
Образ Docker можно создать с помощью специального файла Dockerfile, который содержит инструкции для сборки образа. Эти инструкции могут включать установку зависимостей, настройку среды выполнения, копирование файлов и многое другое.
Когда вы создаете новый образ Docker, он сначала скачивается с репозитория Docker Hub или другого частного репозитория, а затем запускается в контейнере. Образ Docker можно рассматривать как "шаблон" для создания контейнеров, который обеспечивает единообразие и повторяемость при развертывании приложений.
Важно отметить, что образы Docker являются легковесными и могут быть легко перенесены между различными серверами и облачными платформами благодаря своей стандартизации и портативности. Кроме того, образы Docker помогают обеспечить безопасность, поскольку каждый контейнер работает в изолированной среде, что снижает риск атаки на другие приложения или систему хоста.

Docker container
Docker container, или контейнер Docker, представляет собой изолированную среду, в которой выполняются приложения. Контейнеры Docker основаны на ядре операционной системы Linux и используют технологию cgroups для контроля над ресурсами и namespace для изоляции процессов.
Каждый контейнер Docker содержит полный набор зависимостей и конфигураций, необходимых для работы приложения, что позволяет ему быть полностью автономным и независимым от среды, в которой он запускается. Это обеспечивает высокую степень портативности и надежности при развертывании приложений.
Создание контейнера начинается с образа Docker, который является шаблоном для создания контейнеров. Образ Docker содержит все необходимые зависимости и настройки, а контейнер Docker - это экземпляр этого образа, в котором запущено приложение.
Контейнеры Docker можно легко клонировать, масштабировать и управлять ими, что делает их идеальным решением для DevOps и облачных приложений.
Так же невозможно не упомянуть про DockerHub. DockerHub - это крупнейший репозиторий образов Docker, который предоставляет платформу для обмена, совместного использования и хранения образов Docker. DockerHub предлагает бесплатные и платные аккаунты, которые предоставляют различные возможности, включая частные репозитории, тегирование, уведомления и многое другое.
Пользователи могут загружать свои собственные образы Docker на DockerHub, что позволяет другим пользователям использовать эти образы для своих проектов. Это особенно полезно для разработчиков, которые хотят использовать проверенные и надежные образы Docker для своих приложений.
Кроме того, DockerHub также предоставляет инструменты для поиска и просмотра информации об образах Docker, таких как количество звезд, последние обновления, команда, стоящая за образом, и отзывы пользователей.
Для использования DockerHub, вы должны зарегистрироваться и создать свой аккаунт. Затем у вас появляется возможность загружать свои образы Docker, искать и скачивать образы других пользователей, а также следить за обновлениями и новостями в сообществе Docker.


Практика

  1. Скачиваем образ Ubuntu 18.10 при помощи команды pull(выгрузка из реестра):

  1. docker run <image> <опциональная команды, которая выполнится внутри контейнера>

  • В данном примере мы имеем образ ubuntu;

  • echo - вывод строки в консоль;

  1. docker ps
    Команда, которая позволяет нам просматривать запущенные контейнеры, атрибут -a помогает увидеть когда-либо запущенные контейнеры, а не только активные

  1. Исходя из результатов выполнения команды, можно понять, что благодаря такому виду команды мы имеем возможность работать с докером и выполнять в нем команды до выполнения команды exit используя атрибут -it
    Теперь пройдем все базовые этапы становления докера

  1. Создание Dockerfile

  • FROM - выбор системы в которой будут осуществляться последующие инструкции

  • COPY - Копирует файл с основной системы в контейнер (копируем файл test внутрь контейнера, с одноимённым названием)

  • RUN - Выполнение shell-команды из терминала контейнера (в нашем примере, присвоим права на выполнение скрипта _/test)

  • CMD - Выполняет эту команду каждый раз, при новом запуске контейнера

  1. Сборка (создание образа):

В ходе сборки вы можете отслеживать как построчно выполняются инструкции, чтобы в случае ошибки вы знали где искать неисправность вашего файла.
--tag задает имя контейнера.
3. Результат:

Основные уязвимости

Основные уязвимости в docker-образах можно разделить на следующие категории:

  1. OS Vulnerabilities: Уязвимости операционной системы, на которой работает Docker, могут повлиять на безопасность контейнеров. Например, если базовый образ Docker содержит уязвимые системные пакеты, это может стать точкой входа для злоумышленников.

  2. Dependencies: Уязвимости в сторонних зависимостях, таких как библиотеки и фреймворки, могут быть использованы для атаки на контейнеры. Например, уязвимость в библиотеке, используемой приложением в контейнере, может позволить злоумышленнику получить доступ к контейнеру.

  3. Software Vulnerabilities: Уязвимости непосредственно в коде приложений, которые запускаются в контейнерах, могут быть использованы для атак. Например, уязвимость в веб-приложении, запущенном в контейнере, может позволить злоумышленнику выполнить произвольный код на сервере.

  4. Dockerfile: Небезопасные инструкции для сборки образа Docker могут привести к уязвимостям. Например, если в Dockerfile не указаны правильные права доступа к файлам, это может привести к тому, что злоумышленник сможет изменить или удалить важные файлы в контейнере. Важно отметить, что Docker предоставляет инструменты для обнаружения и устранения уязвимостей, такие как Docker Bench for Security и Docker Security Scanning. Однако, безопасность Docker зависит от правильной конфигурации и управления уязвимостями. Для того чтобы подкрепить свои слова приведу вам реальный пример реализации уязвимостей в некой компании:

  • Злоумышленники, воспользовавшись уязвимостью в Microsoft Exchange Server, добыли из почтового ящика пароль от административной панели bitrix для dev-сайта, который был переслан обычным plain-text.

  • В административной панели bitrix есть инструмент «командная php-строка», с помощью которой можно выполнять любой php-код. Воспользовавшись этим и задействовав внешний VPS сервер для получения reverse shell, был получен доступ к системе внутри контейнера.

  • После чего злоумышленники провели атаку на повышение привилегий, использовав уязвимость cve-2022-0847 в ядре linux (уязвимы версии, начиная с 5.8 и до 5.16.11, 5.15.25, и 5.10.102), и получили root-доступ в контейнере.

  • В контейнере были запущены apache и php, требовавшие определенные capabilities для работы, в частности, cap_dac_read_search и cap_dac_override. Использовав их для выхода из контейнера, злоумышленники сумели получить доступ к диску хоста.

  • На хост-машине хранились бэкапы prod-сайта, включая хеши административных учетных записей в формате md5.salt, далее был произведен оффлайн брут, и повтор пунктов 2-5 в prod-окружении… Подводя итог вышесказанному можно сделать вывод, правильная настройка и базовая безопасность (в виде тех же самых паролей) являются фундаментом в построении безопасной системы.

Заключение

В данной статье мы рассмотрели основы Docker и его уязвимости, а также обсудили важность правильной конфигурации и управления уязвимостями для обеспечения безопасности контейнеров. Docker - это мощный инструмент, который может значительно упростить процесс развертывания и управления приложениями, но требует правильного использования и постоянного внимания к безопасности.

Подпишись на LHMedia:

Life-Hack - Хакер / Хакинг
Новостной канал
Канал с бесплатными видео курсами
Юмор

Комментарии (3)


  1. DaemonGloom
    27.04.2024 06:07
    +5

    Я всё понимаю, вам очень хочется прорекламировать свои каналы.

    Но статья, использующая ubuntu 18.10 и помещённая в хаб "информационная безопасность"- это уже за гранью разумного.