Я работаю в IT больше 20 лет, но как-то руки не доходили до контейнеров. В теории я понимал, как они устроены и как работают. Но поскольку я никогда с ними не сталкивался на практике — я не был уверен в том, как именно крутятся-вертятся у них шестерёнки под капотом.
Кроме того, я был без понятия о том, как у них с безопасностью. Но опять же, теория звучит красиво, а старая песня «при росте безопасности падает удобство использования» засела у меня в голове. Так что я подумал, что раз всё так легко делать с контейнерами, то безопасность там ниже плинтуса. Как оказалось, я был прав.
Для быстрого старта я записался на курсы Black Hat 2020 под названием «Из грязи в князи: проникновение и защита окружений Docker Swarm и Kubernetes».
Курс, который проводили Sheila A. Berta и Sol Ozzan, сразу же начался с описания того, как работают контейнеры Docker, а также какой путь они проходят при разворачивании в Kubernetes. Это было полностью практическое занятие — студенты должны были предварительно перед занятиями установить Docker и microk8s на свои машины — отличный способ увидеть взаимодействие инструментов между собой, найти слабые места и, что самое важное, попробовать их блокировать.
К сожалению хоть курсы и обещали стать «князем» спустя два дня, я чувствовал, что все только начинается, и мне еще предстоит многому научиться.
Прежде чем окунуться в мои высокие наблюдения, важно объяснить, что такое контейнер. В мире разработки считается нормальной ситуация, когда код, написанный на вашей личной машине, работает идеально, но при попытке запустить его где-то на сервере — он просто не работает. Контейнеры пытаются преодолеть эту проблему предоставляя автономные машины, которые вы можете легко переносить с одного сервера на другой, зная, что они будут всегда работать. Как видно из имени, они содержат код, библиотеки и другое ПО, нужное для работы. Kubernetes, с другой стороны, является платформой оркестрации для контейнеров. В принципе с его помощью можно бесшовно управлять сотнями или тысячами различных контейнеров.
Ниже приведены некоторые мои выводы с точки зрения красной и синей команды.
Красная команда
Большинство содержимого контейнеров запускается под root: это значит, что если скомпрометировать контейнер, вы получите полный доступ к контейнеру. Это делает последующие шаги значительно более легкими.
Монтирование docker.sock внутри контейнера опасно: если вы получили root внутри контейнера, а также установили Docker внутри контейнера, имеющего сокет Docker (/var/run/docker.sock), у вас есть потенциальная возможность исследования целого кластера, включая доступ к любому другому контейнеру. Такой доступ невозможно предотвратить ни сетевой изоляцией, ни другими способами.
Переменные окружения часто содержат секретные данные: в большинстве случаев люди отправляют пароли в контейнер с использованием обычных переменных окружения. Так что если вы имеете доступ к учетной записи, вы можете подсмотреть эти переменные окружения с целью расширить потом свои полномочия.
Docker API может выдать кучу информации: Docker API, при настройке по умолчанию, работает без авторизации и может выдавать кучу информации. Используя Shodan можно легко найти список открытых портов, потом получить подробную информацию о кластере — и перейти к его полному захвату. TrendMicro написали об этом интереснейшую статью.
Синяя команда
Не запускайте содержимое контейнеров под root: несмотря на то, что под root запускать проще, вы не должны этого делать. Вместо этого запускайте приложения с сброшенными правами отобразив uid либо с помощью параметра --user при работе с CLI, либо указывая USER в Dockerfile.
Не разрешайте установку программ в контейнерах: почти каждая атака начинается с установки чего-нибудь. Начиная с nmap и заканчивая ifconfig и самим Docker (внутри контейнера), установка чего-либо в контейнере была обычным делом. По этой же причине всегда нужно блокировать все неиспользуемые порты. Это также помогает предотвратить передачу управляющих команд при заражении вашей машины. Кроме предотвращения установки программ, стоит убедиться в том, что в самом контейнере установлено минимальное число приложений, нужное для выполнения задачи.
Защищайте docker.sock: его надо защищать, поскольку через этот сокет обрабатывается связь между контейнером и кластером. Поскольку я не хочу вникать в детали в этой статье, почитайте заметку от Docker, что может случиться, а также как это все заблокировать.
Используйте секреты Docker вместо переменных окружения: Секреты есть примерно с 2017 года. Хотя это и небезопасно, но все же лучше, чем переменные окружения для передачи секретных данных в контейнер.
Если статья вызвала у вас интерес к контейнерам — можно достаточно легко установить Docker и\или microk8s (небольшая версия Kubernetes). Здесь есть инструкции по установке Docker для Linux и MacOS, а здесь — инструкции по установке microk8s для Windows, Linux и MacOS.
После установки можно пройти это руководство по быстрому старту от Docker, сходный вариант предлагается и для microk8s.
Если есть желание и\или необходимость пройти комплексный курс по Docker, в котором спикеры-практики разбирают все его инструменты: от основных абстракций до параметров сети, нюансов работы с различными ОС и языками программирования, то попробуйте «Видеокурс по Docker». Вы познакомитесь с технологией и поймете, где и как лучше использовать Docker. А заодно получите best practice кейсы — лучше обучаться в безопасности и с поддержкой практиков на историях о граблях, чем лично на самих граблях с шипованными ручками.