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

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

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

Мы провели небольшое исследование и обнаружили более 350 незащищенных кластеров K8s, принадлежащих различным организациям, проектам с открытым исходным кодом и частным лицам. По меньшей мере 60% из них подвергались взлому или становились жертвами внедрения вредоносных программ и бэкдоров.

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

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

Поиск незащищенных кластеров K8s

Для поиска неправильно сконфигурированных или уязвимых хостов хакеры чаще всего используют поисковые системы вроде Shodan, Censys и Zoomeye. Незащищенные хосты в интернете также можно найти, сканируя диапазоны IP-адресов с помощью ботнетов или таких инструментов, как masscan и Zgrab.

Рисунок 1. Итоги поиска.
Рисунок 1. Итоги поиска.

Первоначально полученное нами число незащищенных кластеров — около трёх миллионов! — поражало воображение. Тогда мы изменили поисковые запросы так, чтобы отыскать именно API-серверы, которыми могут воспользоваться злоумышленники.

На протяжении трех месяцев мы сканировали интернет с помощью системы Shodan. Сходу нашлось 120 IP-адресов, каждый последующий еженедельный поиск добавлял ещё по 20 —  всего набралось чуть более 350 уникальных IP-адресов.

Результаты

Исследовав все 350+ найденных хостов, мы выявили, что у 72% из них открыты HTTPS-порты 443 и 6443, у 19% — HTTP-порты 8001 и 8080, у остальных 9% — менее распространенные порты, такие как, например, 9999.

Распределение по хостам показало, что 85% кластеров содержат от 1 до 3 узлов. Доля кластеров с количеством узлов от 20 до 30 совсем незначительна — вероятно, это или большие компании, или очень крупные кластеры.

По географическому распределению видно (рис. 2), что большинство серверов располагается в Северной Америке. Значительная их часть — целых 80% — связана с AWS. Для сравнения, на долю различных китайских облачных провайдеров приходится около 17% серверов.

Рисунок 2. Географическое расположение кластеров
Рисунок 2. Географическое расположение кластеров

Сервер API используется для доступа к секретам Kubernetes. Если он полностью открыт, то жизнь злоумышленников сильно упрощается — они получают абсолютный контроль над кластером. При этом кластеры Kubernetes зачастую хранят не только свои собственные секреты. Во многих случаях такой кластер является частью жизненного цикла по разработке программного обеспечения (SDLC), поэтому ему необходим доступ к системам управления исходным кодом (SCM), системам непрерывной интеграции и непрерывного развертывания (CI/CD), реестрам и провайдерам облачных услуг.

То есть в секретах Kubernetes хранится куча дополнительной конфиденциальной информации, связанной с различными окружениями. Сюда входят SCM-окружения (такие как GitHub), CI-платформы (Jenkins), различные реестры (Docker Hub), внешние сервисы баз данных (Redis, PostgreSQL) и многое другое.

Анализ перечня владельцев кластеров показал, что в их число входят малые, средние и просто крупные предприятия, а также гиганты из списка Fortune 500. Любопытно, что во время исследования нам попадались и проекты с открытым исходным кодом — их компрометация может привести к заражению всей цепочки поставок ПО и затронуть миллионы пользователей.

В качестве иллюстрации возможных последствий использования незащищенного кластера K8s приведем пример небольшой аналитической компании. Вряд ли ее взлом сам по себе привлек бы широкое внимание СМИ. Однако один из ее клиентов — мультинациональная корпорация из списка Fortune 500 с многомиллиардными доходами.

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

Что можно найти в незащищенных кластерах K8s?

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

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

При этом достаточно иметь доступ к серверу API, чтобы вытянуть начальную информацию. Ниже приведены примеры команд, которые позволяют это сделать:

Команда

Применение

‘/api/v1/pods’ 

Вывести доступные поды

‘/api/v1/nodes’ 

Вывести доступные узлы

‘/api/v1/configmaps’ 

Вывести конфигурации кластера K8s

‘/api/v1/secrets’ 

Вывести все секреты, хранящиеся в etcd.

Секреты часто содержат данные о внутренних и внешних реестрах. Было много случаев, когда разработчики настраивали конфигурационный файл для реестра (например, .dockerconfig), внутри которого находились ссылки на другие окружения, секреты или учетные записи (например, облачного провайдера, внутренней службы или Docker Hub).

Обладание такими данными позволяет значительно расширить вектор атаки. Злоумышленники могут извлечь IP-адреса, конфиденциальную информацию, загрузить в реестр вредоносный код (если ключ позволяет это сделать). Случалось, что в файлах хранились секреты к системам управления исходным кодом, таким как GitHub, GitLab, Bitbucket. Имея токены доступа, хакеры могут клонировать git-репозиторий. В некоторых случаях получается даже загружать в системы контроля версий новый вредоносный код (опять-таки, если ключ позволяет).

Рассмотрим следующий пример. Предоставление универсального доступа к списку подов на первый взгляд может показаться безобидным. Но как всё изменится, если разработчик решит добавить секреты в переменные окружения? Несложно догадаться, что содержится в следующих строках:

Рисунок 3. Снимок экрана со списком подов. Видно, что разработчики по ошибке вставили секреты в переменные окружения.
Рисунок 3. Снимок экрана со списком подов. Видно, что разработчики по ошибке вставили секреты в переменные окружения.

Как показано на рис. 3, переменные окружения подов, которые вывели с помощью /api/v1/pods, содержат чрезвычайно важные секреты, влияющие на операционные аспекты деятельности организации. К ним относятся учетные данные: облачного провайдера (в нашем случае AWS), различных СУБД, служб электронной почты и телефонной связи, сервисов приложений Google и других.

Еще одним потенциальным вектором атаки в кластере Kubernetes является доступ к внутренним сервисам, которые зачастую работают без аутентификации. Когда же аутентификация потребуется, злоумышленник найдет учетные данные в пространстве секретов самого кластера. К сервисам типа ClusterIP, обеспечивающим доступ в http- и https-приложения, можно обратиться с помощью URL следующего вида:

https[:]//IP-ADDRESS[:]PORT/api/v1/namespaces/the-service-namespace/services/https:servicename:port/proxy

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

Рисунок 4. Внутренний сервис Harbor разрешает доступ к закрытому проекту.
Рисунок 4. Внутренний сервис Harbor разрешает доступ к закрытому проекту.

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

Рисунок 5. Запросы к внутреннему сервису Elasticsearch могут быть посланы извне.
Рисунок 5. Запросы к внутреннему сервису Elasticsearch могут быть посланы извне.

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

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

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

Сервер API используется для запуска контейнеров в подах. Атакующая сторона может запустить контейнер (или выполнить exec в существующем) и попытаться через сервер метаданных получить учетные данные для определенной роли в кластере.

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

Рисунок 6. Множество незащищенных ключей. На рисунке показана выдача для одной из учетных записей GCS, которая содержит приватные ключи и ключи доступа.
Рисунок 6. Множество незащищенных ключей. На рисунке показана выдача для одной из учетных записей GCS, которая содержит приватные ключи и ключи доступа.

Активные кампании против кластеров K8s

Обнаружилось, что примерно 60% кластеров активно атакуется криптомайнерами. Мы создали кластер-приманку с различными компонентами, которая два года собирала информацию об атаках.

Удалось выявить, что в настоящее время действуют три основные кампании, направленные на майнинг криптовалют:

  • сбор секретов с незащищенных кластеров и проверка того, как их можно использовать;

  • атака, получившая название RBAC buster;

  • ботнет, запущенный TeamTNT.

Криптомайнинговые кампании

Lchaia/xmrig

Одного запроса на сервер API достаточно, чтобы запустить DaemonSet, который разместит на узлах поды. В ходе одной такой кампании было произведено более 1,4 млн. запросов.

Хакер развернул контейнерный образ lchaia/xmrig:latest из Docker Hub. Как видно из названия, это майнер xmrig, который добывает криптомонеты Monero. Использовался майнинг-пул moneroocean.stream (44.196.193.227) и кошелек с идентификатором 47C9nKzzPYWJPRBSjPUbmK7ghZDk3zfZx9kXh9WyetKS8Dwy7eDVpf4FKVctsuz48UEcJLt53SEFBYYWRqZi3TxhMcbGWub.

Рисунок 7. Образ контейнера lchaia/xmrig в Docker Hub с более чем 1 млн. загрузок.
Рисунок 7. Образ контейнера lchaia/xmrig в Docker Hub с более чем 1 млн. загрузок.

Нам удалось найти профиль его автора на GitHub.

Атака не была единичной. Злоумышленник использовал выходной узел TOR для сокрытия своего IP-адреса и провел атаку 282 раза подряд.

Рисунок 8. Настройки DaemonSet’а для контейнера lchaia/xmrig в нашей приманке.
Рисунок 8. Настройки DaemonSet’а для контейнера lchaia/xmrig в нашей приманке.

ssww

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

Рисунок 9. Команда для принудительного завершения конкурирующих кампаний.
Рисунок 9. Команда для принудительного завершения конкурирующих кампаний.

Затем атакующая сторона с помощью команды cron создает DaemonSet, который монтирует файловую систему хоста с root-правами. Таким образом, cron создается непосредственно на хосте (на самом деле, на каждом хосте/узле), что не только затрудняет устранение последствий в случае, если неправильная конфигурация будет обнаружена, но и обеспечивает высокие привилегии на каждом из скомпрометированных хостов. При выполнении cron инициируется атака, запускающая криптомайнер.

Рисунок 10. Атака ssww, зафиксированная в нашей приманке
Рисунок 10. Атака ssww, зафиксированная в нашей приманке

Dero

Первоначально об этой кампании сообщила CrowdStrike. Однако в их отчете речь шла только об образе контейнера pauseyyf/pause:latest, в то время как под учетной записью alpineyyf обнаружились и другие «популярные» образы.

Образ pauseyyf/pause  скачали 10 тыс. раз, alpineyyf/pause — 46 тыс., alpineyyf/alpins — более 100 тыс.

Рисунок 11. В рамках кампании Dero образы контейнеров скачиваются из Docker Hub; у этого образа количество загрузок превышает 100 тыс.
Рисунок 11. В рамках кампании Dero образы контейнеров скачиваются из Docker Hub; у этого образа количество загрузок превышает 100 тыс.

RBAC buster

Еще одна кампания, которая обнаружилась в рамках нашего исследования. Использует RBAC для создания хитро завуалированного бэкдора (англ.).

TeamTNT

Недавно сообщалось о новой крайне агрессивной кампании от хакерской группы TeamTNT. В рамках своей кампании TeamTNT ищет и собирает токены поставщиков облачных услуг (AWS, Azure, GCP и других). См. статьи [1][2] (англ.)

Затем эти учетные данные используются для получения дополнительной информации об облачном аккаунте и возможных целях: хранилищах данных (например, S3 и BLOB), сервисах вроде Lambdas, функциях и т. п.

Основные векторы атак

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

Ошибка 1. Анонимный пользователь с высокими привилегиями

Во многих случаях неаутентифицированные запросы к кластеру включены по умолчанию. Таким образом, любой может послать запрос и понять, что он взаимодействует с кластером K8s (без получения доступа). Это справедливо как для нативных кластеров Kubernetes, так и для кластеров под управлением некоторых облачных провайдеров (рис. 12).

Рисунок 12. Флаг anonymous-auth включен в конфигурацию кластера EKS по умолчанию.
Рисунок 12. Флаг anonymous-auth включен в конфигурацию кластера EKS по умолчанию.

Как показано на рис. 13, DevOps-инженеры и разработчики сначала проходят аутентификацию и только затем авторизацию.

Рисунок 13. Последовательность аутентификации в K8s
Рисунок 13. Последовательность аутентификации в K8s

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

Рисунок 14. Последовательность аутентификации в K8s в случае, если анонимные запросы разрешены
Рисунок 14. Последовательность аутентификации в K8s в случае, если анонимные запросы разрешены

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

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

Это же всего один YAML до катастрофы! Простая ошибка в конфигурации может привести к полной незащищенности кластера. А вот и пример такой ошибки, обнаруженной нами:

Рисунок 15. Конфигурационный файл, который мы получили из незащищенного кластера, найденного в интернете. Кластер состоял из 7 узлов и принадлежал крупной компании.
Рисунок 15. Конфигурационный файл, который мы получили из незащищенного кластера, найденного в интернете. Кластер состоял из 7 узлов и принадлежал крупной компании.

Ошибка 2. Незащищенный прокси

Другая распространенная ошибка, которую мы обнаружили в ходе нашего исследования — неправильная конфигурация команды kubectl proxy. Как показано на рис. 16, при выполнении kubectl proxy происходит перенаправление авторизованных и аутентифицированных запросов на сервер API.

Рисунок 16. Запуск kubectl proxy на рабочей станции.
Рисунок 16. Запуск kubectl proxy на рабочей станции.

Если эту команду запустить с флагами --address=`0.0.0.0` --accept-hosts `.*`, то прокси на рабочей станции будет прослушивать и пересылать авторизованные и аутентифицированные запросы на API-сервер с любого узла, подключенного к ней по HTTP. При этом надо помнить, что привилегии у них будут такие, как и у пользователя, выполнившего команду kubectl proxy.

Рисунок 17. Утилита kubectl-прокси на рабочей станции «слушает» весь интернет.
Рисунок 17. Утилита kubectl-прокси на рабочей станции «слушает» весь интернет.

Следует иметь в виду, что в некоторых публикациях советы использовать kubectl proxy для самых разных целей раздаются направо и налево. Например, есть руководства, которые рассказывают об установке Kubernetes Dashboard и предлагают выполнять команды без явного предупреждения о возможных последствиях. См. примеры [1][2][3] (англ.)

Резюме и меры по смягчению последствий

Мы рассмотрели критические ошибки, которые часто встречаются в конфигурации сервера API кластера K8s, и уделили особое внимание двум — привязке роли администратора к анонимному пользователю и свободному доступу к прокси-серверу kubectl. Подобные ошибочные конфигурации встречаются повсеместно в организациях самого разного масштаба. Разве это не свидетельствует о пробелах в понимании управления безопасностью в K8s⁈

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

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

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

  2. Защита kubectl proxy. Необходимо проследить, чтобы утилита не была подключена к интернету, находилась в защищенной сетевой среде, а работать с ней могли только аутентифицированные и авторизованные пользователи.

Примечание переводчика

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

Для снижения рисков можно воспользоваться платформой Aqua, которая предлагает пользователям дополнительные меры:

  • Управление доступом на основе ролей (RBAC). RBAC — это нативная функция K8s, которая позволяет ограничить круг и права лиц, имеющих доступ к API Kubernetes. Анонимному пользователю нельзя присваивать роль администратора! Необходимо следить за тем, чтобы у каждого пользователя были только необходимые полномочия — то есть, строго придерживаться принципа наименьших привилегий.

  • Внедрение политик контроля доступа. Admission-контроллеры K8s могут перехватывать запросы к API-серверу перед их выполнением, что позволяет определять и применять политики, повышающие безопасность — в том числе, использовать средства контроля допуска, которые предотвращают привязывание любой роли к анонимной. Платформа Aqua позволяет задать такую политику и защитить кластеры наилучшим образом.

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

Сканер Aqua для нативных облачных сред — включая контейнеры, репозитории кода, виртуальные машины, кластеры Kubernetes и облачных провайдеров — позволяет получить спецификацию программного обеспечения (SBOM), найти уязвимости и ошибки в конфигурации, незащищенную конфиденциальную информацию и секреты. С его помощью можно проверить кластеры K8s на наличие избыточных прав RBAC и незащищенных рабочих нагрузок.

Кроме того, можно сканировать среды исполнения, получая доступ к сотням событий, которые помогают понять поведение систем и приложений. Aqua отслеживает низкоуровневую активность систем и помогает обнаруживать связанные с безопасностью аномалии на более высоких уровнях. Одним словом, Aqua — отличный инструмент для мониторинга кластеров K8s на предмет подозрительного поведения, подобного описанному выше.

Для поиска слабых мест в системе безопасности кластеров Kubernetes можно использовать инструмент автоматизированного тестирования на проникновение Kube Hunter, который позволяет регулярно проводить сканирование и по его результатам принимать соответствующие меры. 

Платформа Aqua позволяет запускать Kube Hunter и с его помощью искать ошибочные конфигурации, которые угрожают кластеру. Ниже на скриншоте видно, что сервер API возвращает анонимному пользователю информацию о состоянии кластера.

Можно кликнуть по тесту и получить дополнительную информацию. В данном случае присутствует привилегированный контейнер. Злоумышленник, получив доступ к кластеру, может использовать его для повышения привилегий. Другие элементы контроля, такие как API Server Hunter, могут указывать на то, что кластер не защищен или допускает утечку секретов.

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

P.S.

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

Смотрите также на нашем YouTube-канале:

Комментарии (4)


  1. slonopotamus
    23.08.2023 18:13
    +1

    Я не понял. Ну допустим у меня торчит наружу порт 6443. Но разве через него по дефолту можно хоть что-то делать без аутентификации?


    1. Expurple
      23.08.2023 18:13
      +2

      В треде на hackernews есть пояснения


  1. Frankenstine
    23.08.2023 18:13

    Статья, судя по всему, не актуальна, опоздала примерно на год. В частности, system:anonymous уже нужно явно задавать, такая роль изначально просто отсутствует, и на всякие там /api/vi/pods будет ответ `forbidden: User "system:anonymous" cannot list resource`

    Более веротяно проникновение в кластер через уязвимости в софте, частично защититься от чего позволяют политики securityContext для контейнеров, имеющих ингрессы, например allowPrivilegeEscalation: false, runAsNonRoot: true и readOnlyRootFilesystem: true, но об этом как раз ни единого слова.


    1. TimurTukaev
      23.08.2023 18:13

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