Проблемы безопасности docker

для macOS и Windows

Docker v 18.03 и выше (с 21 марта 2018 года)

используйте свой внутренний IP-адрес или подключитесь к специальному DNS-имени который разрешится на внутренний IP-адрес, используемый хостом.

поддержка Linux в ожидании https://github.com/docker/for-linux/issues/264

MacOS с более ранними версиями Docker

Докер для Mac v 17.12-v 18.02

то же, что и выше, но используйте вместо.

Докер для Mac v 17.06 — V 17.11

то же, что и выше, но используйте вместо.

Docker для Mac 17.05 и ниже

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

затем убедитесь, что ваш сервер прослушивает IP-адрес, упомянутый выше, или . Если он слушает localhost он не будет принимать соединения.

затем просто укажите контейнер docker на этот IP-адрес, и вы можете получить доступ к хост-машине!

для проверки вы можете запустить что-то вроде внутри контейнера.

псевдоним будет сброшен при каждой перезагрузке, поэтому создайте сценарий запуска, если необходимый.

решение и дополнительная документация здесь:

Бонус от переводчика

В качестве логичного дополнения к этой статье публикуем список из 10 популярных Open Source-утилит для обеспечения безопасности в Docker. Он был заимствован из (за авторством Bill Doerrfeld из Doerrfeld.io).

Ещё одну хорошую подборку практических рекомендаций по тому, как сделать Docker безопаснее, можно найти в компании Aqua Security. Многие её советы пересекаются с уже упомянутыми выше, но есть и другие

Например, авторы предлагают организовать мониторинг активности в контейнерах и указывают, на что обратить внимание при использовании Docker Swarm

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

Наконец, для практического знакомства с некоторыми аспектами безопасности Docker: профилями Seccomp и использованием capabilities Linux-ядра в контейнерах — можно пройти соответствующие лабораторные работы на * — см. секцию «Security».

* Про сам этот ресурс мы два года назад, а в ноябре 2018-го с ним случилась очень занимательная (с точки зрения безопасности) история. Если вкратце, то специалистам из CyberArk Software Ltd. удалось его взломать: добиться возможности выполнять команды за пределами контейнеров, т.е. на хост-системе. Прекрасная иллюстрация проблемы безопасности в Docker, не так ли? Обо всех деталях случившегося читайте .

Проверка состояния контейнеров

Если у вас запущено несколько контейнеров Docker, и вы хотите выбрать, с каким именно работать, потребуется вывести их список. Для этого применяется команда ls. Помимо вывода списка контейнеров она выводит также полезную информацию о них. Команда без опций выдает список запущенных контейнеров:

# docker container ls

Опция ‘-a’ указывает команде выводить все контейнеры, а не только запущенные, опция -s выводит размер каждого контейнера:

# docker container ls -a

Команда inspect выдает множество полезной информации о контейнере:

# docker container inspect КОНТЕЙНЕР

Для вывода логов контейнера выполните команду logs:

# docker container logs КОНТЕЙНЕР

Команды для управления контейнерами

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

docker ps

Система выведет примерные результаты:
В этой инструкции разбирался запуск двух контейнеров — с образов hello-world и ubuntu. Хотя сейчас они не активные, но уже расположены в системе. Для просмотра находящихся в системе контейнеров нужно запустить docker ps, добавив параметр -a:

docker ps -a

В терминале отобразится примерный вывод:

Для просмотра последних созданных контейнеров используется опция -l:

docker ps -l

Чтобы запустить остановленный контейнер, необходимо ввести docker start и далее указать идентификатор или имя контейнера. Так выглядит запуск контейнера 2c88170e5391:

docker start 2c88170e5391


Контейнер будет запущен и чтобы просмотреть его статус, используется команда docker ps:

Чтобы выключить активный контейнер, используется команда docker stop с последующим указанием его идентификатора или имени. Здесь уже потребуется воспользоваться именем, которое предоставил контейнеру Docker (peaceful_minsky):

docker stop peaceful_minsky

Также может потребоваться перезапустить контейнер, не отключая его. Это можно сделать командой:

docker stop 2c88170e5391 && docker start 2c88170e5391

или:

docker restart 2c88170e5391

Отдельного внимания заслуживает запуск контейнера docker compose. Так, после смены настроек в файле docker-compose.yml (например, проброс порта) изменения не выполнятся автоматически. Вдобавок, команда restart также не поможет и потребуется выполнить пересборку контейнера, применив для этого команду build. Другими словами, он будет заново создан. Выполнить операцию можно следующей командой:

docker-compose up -d --no-deps --build

После чего отобразится похожий вывод:

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

Когда контейнер уже не нужен для дальнейшей работы, его можно удалить, набрав в терминале docker rm с добавлением его имени или идентификатора. Для поиска этих данных, которые связаны с hello-world, вводится команда:

docker ps -a

После чего можно приступать к удалению контейнера.

docker rm hello/root_my-test_1

Чтобы осуществить запуск нового контейнера с присвоением ему имени, предусмотрена опция —name. Также можно воспользоваться опцией —rm, позволяющей создавать контейнер, который будет автоматически удален после его остановки. Более подробную информацию о данных и других параметрах можно получить после ввода docker run help.

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

Как сохранить изменения в новый образ?

Во время запуска контейнера из существующего образа у пользователя есть возможность создавать или удалять файлы, аналогично работе на виртуальной машине. При этом изменения будут распространяться только в определенном контейнере. Доступна и возможность запуска с последующей остановкой контейнера, но после его удаления с помощью docker rm будут утеряны внесенные изменения.

Соответственно, следует ознакомиться со способом сохранения текущего контейнера как нового образа.

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

Соответственно, следует сохранить результаты в текущем образе предложенной ниже командой:

docker commit -m "What you did to the image" -a "Author Name" container_id repository/new_image_name

Добавление опции -m дает возможность указать сообщение подтверждения. Это позволит будущим пользователям образа понять, что именно было изменено. Что касается параметра -a — с его помощью можно указать, кто его создатель. container_id является тем же идентификатором, который был использован ранее, во время запуска интерактивной сессии в Docker.

Если вы не занимались до этого созданием новых репозиториев в Docker Hub, имя создаваемого репозитория по умолчанию будет названо именем вашего пользователя в Docker Hub.

К примеру, с именем пользователя admin и идентификатором 2c8ec46adae1 команда должна иметь следующий вид:

docker commit -m "added Node.js" -a "admin" 2c8ec46adae1 admin/ubuntu-nodejs

После того, как образ будет подтвержден (commit) он сохраняется на компьютере локально. Далее будет рассмотрен пример его отправки в репозиторий Docker, чтобы он стал доступным и для других пользователей. Если же посмотреть список образов по завершении этой операции, в нем будет добавлен новый образ, причем исходный также останется на месте:

docker images

Ниже показан примерный результат проверки:

В предложенном выводе ubuntu-nodejs является созданным образом на базе уже имеющегося ubuntu, загруженного в Docker Hub. Проведенные изменения можно увидеть по тому, насколько изменился размер образа. Поскольку изменение касалось только инсталляции NodeJS, при необходимости запуска Ubuntu с этим предустановленным приложением, можно воспользоваться созданным образом.

Остается отправить свой образ в репозиторий, чтобы остальные пользователи имели возможность создать контейнеры на его базе.

Синтаксис и опции docker run

Синтаксис команды docker run похож на синтаксис других команд Linux и выглядит следующим образом:

$ docker run опции образ команда

Утилите обязательно надо передать образ, на основе которого будет создан контейнер. Образ может быть локальным или указывать на образ, который надо загрузить из сети. Мы рассмотрим это в примерах ниже. Опции позволяют настроить контейнер и параметры его запуска более детально. Сама команда позволяет переопределить программу, которая выполняется после запуска контейнера. Например, выполнив /bin/bash, вы можете подключится к самому контейнеру.

Рассмотрим основные опции утилиты, которые мы будем использовать. Опций очень много, поэтому я не могу перечислить их все:

  • -d — запускает контейнер в фоновом режиме;
  • -t — прикрепляет к контейнеру псевдо-TTY-консоль;
  • -i — выводит в терминал STDIN поток контейнера;
  • —name — имя контейнера, по которому потом можно будет к нему обращаться;
  • —dns — устанавливает DNS-серверы для контейнера;
  • —network — тип сети для контейнера, может принимать такие значения: bridge (используется по умолчанию), none, host. Также можно передать идентификатор сети Docker, к которой надо подключится;
  • —add-host — добавляет строчку в /etc/hosts;
  • —restart — указывает, когда надо перезапускать контейнер. Возможные значения: no, on-failure, always, unless-stopped;
  • —rm — удаляет контейнер после завершения его работы;
  • -m, —memory — количество оперативной памяти, доступное Docker-контейнеру;
  • —memory-swap — объём памяти раздела подкачки, доступный в контейнере;
  • —cpus — количество ядер процессора, доступных в контейнере;
  • —shm-size — размер файла /dev/shm;
  • —device — позволяет монтировать устройства из папки /dev в контейнер;
  • —entrypoint — позволяет переопределить скрипт, который выполняется при запуске контейнера, перед запуском основной команды;
  • —expose — позволяет пробросить несколько портов из контейнера в хост-систему;
  • -P — пробрасывает все порты контейнера в хост-систему;
  • -p — переносит все порты контейнера в хост-систему без смены номера порта;
  • —link — позволяет настроить связь контейнеров Docker;
  • -e — добавляет переменную окружения в контейнер;
  • -v, —volume — позволяет монтировать папки хоста в контейнер;
  • -w — изменяет рабочую директорию контейнера.

Это основные опции, которые мы будем использовать в этой статье, а теперь давайте рассмотрим на примерах, как создать контейнер Docker в Linux.

Работа с командой Docker без прав суперпользователя

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

Если попробовать запустить в терминале Docker без этих прав или, не являясь пользователем группы docker, появится ситуация, когда не запускается контейнер.
Поэтому если нет желания постоянно набирать sudo перед запуском команды, стоит добавить своего пользователя в указанную выше группу:

sudo usermod -aG docker ${USER}

Чтобы применить изменения, потребуется выйти с заново войти на сервер. Можно также воспользоваться этой командой:

su - ${USER}

Продолжить работу можно будет после ввода пароля пользователя. Проверить, что добавление пользователя прошло успешно, можно командой (пользователь sammy):

id -nG

При желании добавить выбранного пользователя в группу, можно указать его имя:

sudo usermod -aG docker username

Последующие шаги предполагают, что пользователь уже добавил себя в группу docker. Если нет желания это делать, перед командами необходимо набирать sudo.

Запуск контейнера Docker

Запущенный ранее hello-world представляет собой пример контейнера, который открывается и закрывается после отображения тестового сообщения. При этом контейнеры предназначены для выполнения более полезных задач. Они имеют много общего с виртуальными машинами, однако требуют намного меньше ресурсов для работы.
Можно рассмотреть, как запустить контейнер при помощи последней версии образа Ubuntu. Добавление опций -i и -t предоставляет доступ в интерактивном режиме к командному процессору:

docker run -it ubuntu

Командная строка изменится, указывая на переход в контейнер, и будет выглядеть таким образом:

Следует обратить внимание, что также отображается идентификатор контейнера. Здесь это 2c88170e5391

Он понадобится позже, чтобы сообщить клиенту, какой именно удалить контейнер.

После этого можно запустить любую команду в контейнере. К примеру, можно обновить базу данных пакетов. Для этого нет необходимости пользоваться командой sudo, поскольку работа ведется от имени пользователя с root-правами:

apt update

Затем появится возможность установки приложений. Рассмотрим пример установки Node.js:

apt install nodejs

Эта команда выполнит установку Node.js в контейнер, используя репозиторий Ubuntu. По завершении установки можно проверить, была ли она успешно выполнена:

node -v

Будет показан номер текущей версии Node.js:

Проведенные изменения в контейнере распространяются только на него. Завершить работу с контейнером можно командой exit.

Сеть в Docker.

Кроме контейнеров и образов Docker оперирует еще и собственными сетями, которых по-умолчанию он устанавливает аж три (
docker network ls ):

  1. bridge
  2. host
  3. none

Контейнеры подключаются к bridge по-умолчанию, а тот уже раздаёт IP адреса из своего диапазона, и через сетевые мосты перенаправляет траффик в большой интернет. Самое приятное: если пытливый программистский разум не вмешивался в настройки Докера, то все контейнеры внутри своей сети могут свободно видеть друг друга и общаться между собой, а снаружи к ним можно достучаться только привязав контейнерные порты к  портам хоста (например,
-p8080 ).

Это настолько круто, что я повторю последнее предложение примером: можно запустить nginx контейнер и не открывать его 80й порт хосту — другие контейнеры из его сети всё еще смогут с ним общаться.

ZSH

docker run -d nginx
#6e47c39f797a71429971e5c2df59305dd5bd2e47bd901e2f404de18a53aefa53
docker inspect —format ‘` `.`NetworkSettings`.`IPAddress `’ 6e4
#172.17.0.2
docker run -ti busybox
#/ #
wget -qO- 172.17.0.2
#<!DOCTYPE html>
#<html>
#<head>
#<title>Welcome to nginx!</title>
#<style>
#…

1
2
3
4
5
6
7
8
9
10
11
12
13

docker run-dnginx

#6e47c39f797a71429971e5c2df59305dd5bd2e47bd901e2f404de18a53aefa53

docker inspect—format’` `.`NetworkSettings`.`IPAddress `’6e4

#172.17.0.2

docker run-ti busybox

#/ #

wget-qO-172.17.0.2

#<!DOCTYPE html>
#<html>
#<head>
#<title>Welcome to nginx!</title>
#<style>
#…

То есть, зная IP адрес контейнера, общаться с ним — не проблема. А вот знать адрес контейнера — проблема. То, что сегодня nginx висит на 172.17.0.2 совсем не значит, что здесь же он будет и завтра. Поменялся порядок запуска контейнера, перенесли его в другую сеть, поменяли настройки Docker-сервера — и айпишка поменялась. Нужно что-то более постоянное.

Ограничьте потребление доступных ресурсов

Что нужно вашему приложению?

Это совершенно легкое приложение, потребляющее не более 50Мb памяти? Тогда зачем давать ему больше? Выполняет ли приложение более интенсивный процессинг, которому требуется 4+ CPU? Тогда дайте ему к ним доступ, но не более того.

Если вы включаете анализ, профилирование и бенчмаркинг в непрерывный процесс разработки, тогда вы должны знать, какие ресурсы необходимы вашему приложению.

Поэтому когда вы разворачиваете контейнеры, убедитесь, что у них есть доступ только к самому необходимому.

Для этого используйте следующие команды для Docker:

Вот пример конфига из :

Больше информации можно найти при помощи команды или же в разделе “” документации Docker.

Большая поверхность атаки

Последний аспект безопасности, который стоит рассмотреть, является прямым следствием того, как работает Docker — и это потенциально очень большая поверхность атаки. Таким рискам подвержена любая IT-организация, но особенно та, что полагается на эфемерную природу контейнерной инфраструктуры.

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

В таких условиях атакам может подвергнуться потенциально намного больше элементов вашей инфраструктуры.

Вы не в курсе статистики развертывания приложений в вашей организации? Тогда задайте себе следующие вопросы:

  • Какие приложения сейчас у вас развернуты?
  • Кто развернул их?
  • Когда их развернули?
  • Почему их развернули?
  • Как долго они должны работать?
  • Кто за них отвечает?
  • Когда их в последний раз проверяли на безопасность?

Надеюсь, вам не очень сложно ответить на эти вопросы. В любом случае, давайте рассмотрим, какие действия можно предпринять на практике.

Внедрите контрольный журнал с правильным логированием

Внутри приложения обычно ведется учет действий пользователя, таких как:

  • Когда пользователь создал свой аккаунт
  • Когда он его активировал
  • Когда пользователь последний раз менял пароль и т.п.

Помимо этих действий следует вести учет действий и по каждому контейнеру, который создается и разворачивается в вашей организации.

Не стоит этот учет излишне усложнять. Следует вести учет таких действий, как:

  • Когда приложение было развернуто
  • Кто его развернул
  • Почему его развернули
  • Каковы его намерения
  • Когда его следует остановить

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

Вдобавок стоит внедрить уведомления по почте или любым другим способом (IRC, Slack или HipChat). Этот прием позволит убедиться, что все могут видеть, когда что разворачивается.

Таким образом, если случилось что-то неподобающее, спрятать это не получится.

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

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

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

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

ОС хоста

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

Правила аудита

Создавайте и используйте правила аудита для файлов, связанных с Docker’ом, с помощью . Например, можно добавить к и перезапустить сервис аудита.

Режим FIPS

Включение режима FIPS заставляет криптографические инструменты переключиться на алгоритмы, внесенные в FIPS (американские — прим. перев.), соответствуя, таким образом, федеральным и отраслевым нормам и требованиям. Если ОС хоста поддерживает режим FIPS, его можно включить, выполнив следующие команды:

Также необходимо включить FIPS в Docker Engine:

Для получения дополнительной информации см. в документации и .

Docker Secrets

Конфиденциальные данные должны храниться как секреты. Запустить соответствующий сервис можно с помощью команды docker service create:

Подробности см. в .

Файл конфигурации Docker’а

Следующие настройки можно добавить в файл конфигурации :

  • — отключает обмен данными между контейнерами, чтобы избежать ненужной утечки информации.
  • — захватывает все логи кроме отладочных.
  • — подключает удаленное ведение логов, пересылает их по указанному адресу. Работает только в том случае, если запущен демон syslog. В качестве опций принимаются TCP и UDP. Также возможно подключение для каждого конкретного контейнера. Для этого устанавливается специальный флаг при запуске Docker’а ().

  • — предотвращает поднятие привилегий (privilege escalation), изолируя пространство имен под конкретного пользователя.

Безопасность транспортного уровня

Возможность подключения к демону Docker’а (если удаленный доступ необходим) должна быть только у пользователей с доступом к учетным данным TLS-клиента.

Плагины авторизации

Определитесь с тем, каким пользователям какие команды разрешено выполнять, и создайте соответствующий плагин авторизации для Docker’а. Затем запустите демон Docker’а и добавьте в него плагин:

Чтобы больше узнать о создании авторизационных плагинов, см. в .

Параметры демона

Демон Docker’а работает с набором параметров по умолчанию.

  • — этот параметр помогает сократить время простоя контейнеров при выключении или перезагрузке системы. Становится проще их патчить или обновлять с минимальным простоем;
  • — когда доступны или используются hairpin NAT’ы, прокси в пользовательском пространстве становится избыточной службой, которая только увеличивает число возможных векторов атаки;
  • — предотвращает получение дополнительных привилегий контейнерами при помощи suid или sguid;
  • — если у вас есть собственный профиль seccomp, можно его применить с помощью этого флага. Узнать больше о Seccomp и Docker можно .

режим моста

Чтобы получить доступ к MySQL, работающему на хосте докера, из контейнеров в режиме моста, необходимо убедиться, что служба MySQL прослушивает соединения по IP-адресу .

Для этого убедитесь, что у вас есть либо либо в вашем конфигурационном файле MySQL (my.cnf).

Если вам нужно установить переменную среды с IP-адресом шлюза, вы можете запустить следующий код в контейнере:

затем в вашем приложении используйте окружения чтобы открыть соединение с MySQL.

Примечание: если вы используете ваш сервер MySQL будет прослушивать соединения на всех сетевых интерфейсах. Это означает, что ваш сервер MySQL может быть доступен из Интернета; убедитесь, что настроили правила брандмауэра соответственно.

Примечание 2: если вы используете ваш сервер MySQL не будет прослушивать подключения к . Процессы, работающие на хосте докера, который хочет подключиться к MySQL, должны будут использовать IP-адрес .

3 ответа

4

По-прежнему имеет смысл вставлять некоторые входящие правила в ваш экземпляр докера, чтобы предотвратить отвращение от атак, но вам придется ограничивать исходящий (Интернет) доступ с любого восходящего роутера, к которому подключается изображение докера. Причина этого заключается в том, что если вы пытаетесь заблокировать исходящий доступ с правилами брандмауэра внутри вашего экземпляра, то, если этот экземпляр скомпрометирован, эти правила могут быть удалены злоумышленником. Блокируя выход через маршрутизатор экземпляра, вы блокируете исходящий доступ даже в случае компрометации — злоумышленнику также придется скомпрометировать маршрутизатор.

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

Первые два правила предназначены для доступа между хостом и контейнером. В третьем правиле говорится (примерно), что все, что не является подсети хоста для SFTP, просто ОК; четвертое — правило исходящего, которое в основном является близнецом к третьему; пятое правило является общим для всех (если есть другие связанные порты, которые используются), хотя это не нужно, вы, вероятно, могли бы удалить его; последнее правило — это магия, которая предотвращает доступ к чему-либо другому, кроме подсети хоста. Поскольку доступ предоставляется в первых нескольких правилах, он никогда не будет срабатывать, если ни одно из предыдущих правил не применимо, и в этом случае мы говорим: «Нам все равно, что вы хотите, вы не соответствовали тому, что вы одобрили, так что вы не можете добраться отсюда ». Входящий трафик извне будет удовлетворен 3-м и 4-м правилами.

1

Это не проблема конкретной докеры. Есть несколько способов решить эту проблему.

  1. Используйте правила stateful , чтобы разрешать входящие и связанные /установленные трафики, а затем блокировать все остальное.

  2. Используйте только службу sftp, например ProFTPD , которая неспособный запустить оболочку.

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

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

Чтобы предотвратить исходящий трафик на не-SSH (SFTP) и веб-портах, вы можете применить политику через IPTABLES или другой брандмауэр Layer4 к DROP или REJECT трафику из сегмента, используемого контейнерами докеров, предназначенными для 0.0.0.0/0 за исключением случаев, когда порт назначения — TCP22.

Чтобы решить проблему «переходить к несанкционированному месту в сети», вам может потребоваться настроить экземпляр прокси-сервера фильтрации /кэширования, например squid или bluecoat, который прослушивает интерфейс docker0 и который использует маршрут defalt хозяина, чтобы выйти в Интернет. Оттуда вы можете применять политику, основанную на многих критериях, а также экономить использование сети, кэшируя статический контент. Возможно, вы захотите использовать NAT (я думаю, что IPTABLES и Masquerade предоставляют это в Linux) на главной машине для обеспечения прозрачного использования прокси (я описал это в своем ответе на ). Это означает, что у вас есть причина выйти в Интернет, в первую очередь, что соответствует политике вашей компании.

Из-за характера SSH (на котором основан SFTP) вы не сможете обеспечить запрет трафика для перемещения файлов, если вы не реализуете политику, в соответствии с которой контейнеры могут использовать только пары ключей, предоставленные вами. Это хорошо для вас, потому что оно дает вам защиту « у меня не было видимости или контроля над переданными файлами », если один из ваших клиентов переносит что-то незаконное (например, нарушение IP-адреса или использует вашу службу для exfiltrate информация, содержащая классификационный ярлык, или они торгуют в CP), если вас привлекают к суду за то, что делают ваши клиенты (думаю, аналогично статусу обычных перевозчиков для телекоммуникационных компаний). Это плохо для вас, потому что вы не можете кэшировать часто повторно переданные, неизменные файлы и потому, что любая политика, которую вы пишете в контракте с вашими клиентами, будет по существу невозможна с помощью технических средств.

4 — Общие данные между несколькими контейнерами Docker

До сих пор мы прикрепляли том к одному контейнеру за раз. Но часто мы хотим несколько контейнеров присоединить к одному тому данных

Это довольно просто сделать, но есть одно важное предостережение: на данный момент Docker не обрабатывает блокировку файлов. Если вам нужно, чтобы несколько контейнеров записывали на том, запущенные в этих контейнерах приложения должны быть сконструированы для записи в общие хранилища данных, чтобы предотвратить повреждение данных.

Создадим Container4 и DataVolume4

Используйте docker run для создания нового контейнера с именем named Container4 с присоединённым томом с данными.

docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu

Далее мы создадим файл и добавим в него текст:

echo "This file is shared between containers" > /datavolume4/Example4.txt

Затем мы выйдем из контейнера.

exit

Это вернёт нас в приглашение командной строки, где мы сделаем новый контейнер, который смонтирует том данных из Container4

Создайте Container5 и смонтируйте тома из Container4

Мы собираемся создать Container5 и смонтировать тома из Container4:

docker run -ti --name=Container5 --volumes-from Container4 ubuntu
cat /datavolume4/Example4.txt

Вывод

This file is shared between containers

Давайте из второго контейнера добавим к нему какой-нибудь текст:

echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt

Наконец мы выходим из контейнера:

exit

Далее мы проверим, что наши данные ещё находятся в контейнере Container4.

Просмотр сделанных изменений в Container5

Давайте проверим изменения, которые были записаны на том данных контейнером Container5, сделаем это перезапустив Container4:

docker start -ai Container4
cat /datavolume4/Example4.txt
cat /DataVolume4/Example4.txt

Вывод

This file is shared between containers
Both containers can write to DataVolume4

Теперь, когда мы убедились, что оба контейнера способны читать и записывать в том данных, выйдем из контейнера:

exit

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

Запуск Container 6 и монтирование тома только для чтения

Когда том был смонтирован в контейнер, вместо его размонтирования, как бы мы сделали с типичной файловой системой Linux, мы создадим новый контейнер и смонтируем тем образом, каким хотим, если нужно, удалим предыдущий контейнер. Чтобы сделать том только для чтения добавьте в конец имени контейнера :ro

docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu

Проверим доступ только для чтения попытавшись удалить наш файл примера:

rm /datavolume4/Example4.txt

Вывод

rm: cannot remove '/datavolume4/Example4.txt': Read-only file system

Наконец, выйдем из контейнера и очистим наши тестовые контейнеры и тома:

exit

Сделано, давайте удалим наши контейнеры и тома:

docker rm Container4 Container5 Container6
docker volume rm DataVolume4

В этом примере мы показали как передавать данные между двумя контейнерами используя тома данных и как монтировать тома данных только для чтения.

Подлинность образов Docker

Описание

В Интернет можно найти немало Docker-образов, которые делают всевозможные полезные и классные вещи, но если вы загружаете образы без использования каких-либо механизмов доверия и проверки подлинности, вы по сути запускаете на своих системах произвольное ПО.

  • Откуда был загружен этот образ?
  • Доверяете ли вы его создателям? Какие политики безопасности они используют?
  • Есть ли у вас объективное криптографическое доказательство того, что образ был действительно создан этими людьми.
  • Вы уверены, что никто не изменил образ после того, как он был загружен?

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

Лучшие практики

  • Обычный здравый смысл: не запускайте непроверенное ПО и/или ПО, полученное из недоверенных источников.

  • С помощью серверов реестров Docker, которые можно найти в этом списке Docker Security Tools, разверните доверенный сервер (trust server).

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

Примеры

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

Если у вас еще нет учетной записи на Docker Hub, заведите ее.

Создайте директорию с простым Dockerfile следующего содержания:

Соберите образ:

Войдите в свою учетную запись на Docker Hub и загрузите образ:

Включите в Docker принудительную проверку доверия:

Теперь попробуйте получить только что загруженный вами образ:

Вы должны получить следующую ошибку:

При включенном DOCKER_CONTENT_TRUST соберите контейнер еще раз. Теперь он по умолчанию будет подписан.

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

Ваши закрытые ключи будут сохранены в директории ~/.docker/trust, ограничьте к ним доступ и создайте резервную копию.

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

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Техноарена
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: