Pull to refresh
Флант
DevOps-as-a-Service, Kubernetes, обслуживание 24×7

Выход за пределы pod'а в Kubernetes через монтирование логов

Reading time 4 min
Views 9K
Original author: Daniel Sagi
Прим. перев.: Эта заметка была написана исследователем ИТ-безопасности из компании Aqua Security, специализирующейся на DevSecOps. Она является прекрасной иллюстрацией тех тонкостей в конфигурации Kubernetes, что важно всегда держать в голове, обслуживая кластеры в production. Конечно, если вы думаете про их безопасность…



Kubernetes состоит из множества компонентов, и иногда их комбинирование определенным образом приводит к неожиданным результатам. В этой статье я покажу, как pod, запущенный с привилегиями root'а и примонтированной директорией /var/log узла, может раскрыть содержимое всей файловой системы хоста пользователю с доступом к его логам. Мы также обсудим варианты решения этой проблемы.

Как Kubernetes видит логи


Задумывались ли вы над тем, как kubectl logs <pod_name> извлекает логи из pod'а? Кто отвечает за сбор логов из контейнеров? И как они попадают на ваш компьютер?

Следующая схема иллюстрирует процесс:



Kubelet создает структуру внутри директории /var/log на хосте, представляющую pod'ы на узле. В директории для нашего pod'а есть файл 0.log (1), но на самом деле это симлинк на лог контейнера, лежащий в /var/lib/docker/containers. Это все с точки зрения хоста.

Kubelet открывает endpoint /logs/ (2), который просто работает с файловым HTTP-сервером в директории (3), делая логи доступными для запросов, поступающих от API-сервера.

Теперь представьте, что мы развернули pod с hostPath, примонтированным в /var/log. У такого pod'а будет доступ ко всем лог-файлам на хосте. Хотя уже это само по себе является потенциальной проблемой, мы можем сделать следующий логический шаг. Что, если заменить 0.log на симлинк к… скажем, /etc/shadow?

│
├── var
│ ├── logs
│ │ ├── pods
│ │ │ ├── default_mypod_e7869b14-abca-11e8-9888-42010a8e020e
│ │ │ │ ├── mypod
│ │ │ │ │ ├── 0.log -> /etc/shadow
│ │ │ │ │ │

Теперь, пытаясь загрузить логи с помощью kubectl logs на клиентской машине, получим:

$ kubectl logs mypod
failed to get parse function: unsupported log format: "root:*:18033:0:99999:7:::\n"

Kubelet переходит по ссылке и читает содержимое файла, на который она указывает (им может быть любой файл на узле).

Поскольку ожидался JSON, kubectl вылетел после первой строки, однако мы можем легко прочитать конкретные строки файла shadow, запуская команду с флагом –-tail=-<line_number>.

Это поразительно. Поскольку kubelet переходит по симлинку, можно воспользоваться его root-правами для чтения любого файла на узле, просто создавая символическую ссылку внутри pod'а.

Побег из pod'а


Пойдем еще дальше. Мы знаем, что при запуске pod'а в Kubernetes в него устанавливается токен ServiceAccount. Таким образом, если service account разрешает доступ к логам, мы можем напрямую получить доступ к kubelet'у и root-привилегии на узле.

Я написал proof of concept (POC), демонстрирующий данный вектор атаки:

  • развертывание pod'а с точкой монтирования /var/log;
  • создание символической ссылки на корневую директорию хоста;
  • чтение закрытого ключа ssh пользователя на хосте.

В следующем видео показаны две особые команды, выполняющиеся внутри pod'а:

  • lsh == ls (на файловой системе хоста);
  • cath == cat (на файловой системе хоста).

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

Все файлы, задействованные в этом POC, можно найти в соответствующем репозитории GitHub. Там же лежит еще один POC-скрипт, который автоматически собирает закрытые ключи и токены ServiceAccount с файловой системы хоста.

Монтирование директорий может быть опасным


Итак, это уязвимость или просто плохая практика?

Развертывание pod'а с открытым для записи hostPath в /var/log встречается редко (кроме того, есть другие способы злоупотребить монтированием секретных директорий хоста в pod). Но даже если вы знали, что монтирование /var/log — сомнительная практика, вы скорее всего не ожидали, что она позволит с такой легкостью завладеть узлом.

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

Этот метод был протестирован на Kubernetes 1.15 и 1.13, но скорее всего затрагивает и другие версии.

Устранение


Такой «побег» возможен только в том случае, если pod работает под root'ом. Вообще этого следует избегать. Aqua CSP позволяет с минимумом усилий задать политику, предотвращающую работу контейнеров под root'ом или выдающую разрешения только определенной группе образов, для которой действительно требуется root.

Другой способ — просто не развертывать pod'ы с hostPath с правами записи в /var/log. Этот подход не задается по умолчанию и не является обычной практикой, поэтому необходимо сознательно его определять (впрочем, возможность по-прежнему остается). Но как проверить?

Мы добавили новый скрипт (hunter) в kube-hunter — наш легковесный Open Source-инструмент для тестирования Kubernetes, — проверяющий кластер на предмет существования pod'ов с такими опасными точками монтирования. (Прим. перев.: Kube-hunter присутствовал в недавнем обзоре утилит для безопасности K8s, что мы публиковали в своем блоге.)

Пользователи Aqua могут защититься от данного риска, используя runtime-политику для запрета монтирования определенных томов:



Прим. перев.: Частично такую проблему можно решить с помощью Pod Security Policies, а именно — AllowedHostPaths. Однако это тоже не защита от симлинков. Наконец, как нам подсказывают в комментариях, можно просто ограничить запуск под root'ом, снова руководствуясь PSP.

Итог


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

P.S. от переводчика


Читайте также в нашем блоге:

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+31
Comments 12
Comments Comments 12

Articles

Information

Website
flant.ru
Registered
Founded
Employees
201–500 employees
Location
Россия
Representative
Тимур Тукаев