В современном мире разработка приложений подразумевает гораздо больше, чем просто написание кода.
Использование нескольких языков, фреймворков и архитектур, а также прерывистые интерфейсы между инструментами на каждом этапе жизненного цикла разработки приводят к огромной сложности.
Docker оптимизирует и ускоряет процесс, предоставляя разработчикам возможность творить, используя предпочитаемые инструменты, стеки приложений и среды развертывания для каждого проекта в соответствии с их потребностями.
🐳 Безопасность контейнеров Docker
Введение
Docker упростил непосредственное развертывание приложений и веб-сайтов без необходимости беспокоиться о зависимостях, настройках конфигурации или версиях пакетов, установленных на сервере.
Из-за его простоты в плане простого получения образа из реджестри и выполнения его с помощью команды (docker run) мы часто не понимаем, что он требует такого же уровня безопасности, как и любая другая структура.
Мы уже писали пару статей о лучших практиках безопасности docker, которые можно найти здесь и здесь.
В этой статье мы рассмотрим некоторые более продвинутые концепции безопасности Docker, которые, безусловно, окажутся полезными, если вы работаете с несколькими контейнерами, хотите предотвратить эскалацию привилегий и т.д.
Nologin Shell
Ваш контейнер Docker может содержать несколько учетных записей пользователей.
Учетная запись root – это наивысшая привилегия, которую пользователь может получить в контейнере, и как только он получает права root, он может выполнять команды root или делать многое другое в контейнере.
Чтобы гарантировать, что злоумышленник не сможет получить root-аккаунт, даже если у него есть доступ к паролю root-аккаунта, вы можете изменить оболочку на nologin.
В качестве альтернативы можно также использовать оболочки с ограниченным доступом для пользователя.
Чтобы отключить вход root (внутри контейнера), достаточно изменить Dockerfile и добавить следующую строку.
RUN chsh –s /usr/bin/nologin root
Оболочки nologin используются для запрета доступа к учетной записи.
Эта настройка гарантирует, что даже если злоумышленник завладеет учетной записью пользователя root, он не сможет войти в систему, так как это запрещено в файле nologin, следовательно, ни один пользователь, даже root, не сможет войти в свою учетную запись.
Отключение эскалации привилегий с помощью SUID
Прежде чем мы поговорим о методах защиты, необходимо понять, что такое SUID.
SUID, что расшифровывается как Set owner User ID up on execution, – это особый тип разрешений, предоставляемых файлу.
Если пользователь root предоставит это разрешение исполняемому файлу, он может быть использован для повышения привилегий до уровня root.
🐍 Как выполнить неисполняемый бинарный файл
Чтобы установить бит SUID, пользователю root достаточно ввести команду
chmod +x <binary_name>
Для предотвращения этого вы можете использовать специальный тег – security-opt=”no-new-privileges” во время создания контейнера docker.
Этот тег гарантирует, что процессы и дочерние процессы (порожденные родительским процессом) не получат никаких дополнительных привилегий, используя бит SUID или SGID.
Например:
Примечание: Здесь image_id – это Id образа вашего контейнера docker. Чтобы найти идентификатор образа вашего контейнера, просто введите docker image ls или docker images
Создание файловой системы только для чтения
Файловая система только для чтения гарантирует, что пользователи не смогут создавать какие-либо файлы в системе.
Это не позволит им загружать и устанавливать вредоносные файлы в контейнер docker, которые в дальнейшем могут быть использованы для других вредоносных целей, таких как вредоносное ПО, кейлоггер или оболочка обратного подключения.
Поэтому очень важно защитить docker от несанкционированного доступа, создав файловую систему только для чтения.
Для создания файловой системы только для чтения мы можем использовать следующую команду
Понятно, что контейнер без прав на запись может доставить пользователям некоторые неудобства.
Поэтому можно создать временную файловую систему.
В этом примере я выбрал каталог /opt для временной файловой системы.
Таким образом, пользователь сможет загружать файлы только в указанный каталог, и они не могут быть перемещены в домашний или любой другой каталог.
Этого можно добиться, выполнив следующую команду.
Предотвращение межконтейнерного взаимодействия
Обычно после установки Docker в производственной среде вы устанавливаете несколько контейнеров, поскольку они отвечают за разные виды деятельности.
Например, вы можете использовать MongoDB в одном контейнере, а приложение размещать в другом.
Однако знаете ли вы, что существует возможность взаимодействия между контейнерами?
Следующий сценарий: Контейнер docker, в котором запущен уязвимый экземпляр приложения, открытый через порт, открыт для внешнего мира.
Злонамеренный пользователь, сидящий в другом контейнере, может поставить под угрозу безопасность всего приложения.
Поэтому, если это не требуется, вы можете предотвратить межконтейнерное взаимодействие.
Для начала можно рассмотреть сети по умолчанию, встроенные в docker.
Здесь мы будем проверять тип сети.
В данном примере мы рассмотрим тип сети bridge.
- 🐳 Примеры, как подключать контейнеры Docker к сети
- 🐳 Docker сетевое взаимодействие 101
- 🐳 Объяснение концепции сетей в Docker
Прокрутив страницу вниз, вы увидите, что для параметра com.docker.network.bridge.enable-icc установлено значение true.
Поскольку несколько устройств и контейнеров могут быть подключены к мостовому соединению, чтобы они могли общаться, мостовые соединения используются для объединения контейнеров и повышения их доступности.
Создание новой сети и установка для нее значения false – это все, что нам нужно сделать, чтобы заблокировать межконтейнерное взаимодействие.
Затем, когда мы создаем новый контейнер, мы можем включить его во вновь созданную сеть, которую мы установили.
В результате контейнер будет отделен и сможет вмещать только один контейнер.
Давайте начнем с создания новой сети:
Прокрутив страницу вниз, вы увидите, что для параметра com.docker.network.bridge.enable-icc установлено значение true.
Поскольку несколько устройств и контейнеров могут быть подключены к соединению типа мост, чтобы они могли общаться, мостовые соединения используются для объединения контейнеров и повышения их доступности.
Создание новой сети и установка для нее значения false – это все, что нам нужно сделать, чтобы заблокировать межконтейнерное взаимодействие.
Затем, когда мы создаем новый контейнер, мы можем включить его во вновь созданную сеть, которую мы установили.
В результате контейнер будет отделен и сможет вмещать только один контейнер.
Давайте начнем с создания новой сети
Здесь мы создали сеть типа мост и установили межконтейнерную связь как false.
Имя созданной нами сети задано как testnet1.
После всего этого мы можем запустить контейнер docker с сетью, заданной как testnet1.
Заключение
В этой статье блога мы обсудили некоторые из наиболее важных особенностей безопасности Docker.
Несмотря на то, что пользователь имеет доступ к паролю root, мы узнали, как блокировать логины root.
В следующих уроках мы узнаем, как избежать эскалации привилегий с помощью файлов SUID или SGID.