[Перевод] Ограничиваем число процессов в pod’е Kubernetes

312930669959cb2c4f7acac80684171a.jpg

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

В этой статье мы обсудим, почему рискованно сохранять в pod«е параметры количества процессов по умолчанию, и как решить проблему.

Конфигурация по умолчанию

По умолчанию в Kubernetes pod«ы наследуют параметры количества процессов у хоста, а на хосте установлено очень большое значение. Узнать его можно командой:

$ cat /proc/sys/kernel/pid_max

Риски конфигурации по умолчанию

Если в pod«е число процессов не ограничено или лимит очень большой, злоумышленник может запустить ветвящуюся бомбу (fork bomb), что приведёт к отказу в обслуживании и сбою системы из-за нехватки ресурсов.

Профилактика

В Kuberbetes 1.20 есть стабильная функция, которая позволяет ограничивать количество процессов в pod«е на уровне ноды в конфигурации kubelet.

Полную конфигурацию kubelet см. здесь.

Давайте посмотрим пример. Что нам понадобится:

  • Работающий кластер Kubernetes (можно использовать minikube или kind).

  • Знакомство с командами kubectl.

  • Общее представление об администрировании Linux.

В этом примере мы используем minikube.

Что делать

Часть 1. Сначала мы проверим конфигурацию по умолчанию — сколько процессов в pod«е разрешено.

Запускаем кластер Kubernetes через minikube:
Примечание. Нужна версия Kubernetes не ниже 1.20. На момент написания статьи minikube использовал версию 1.23.3.

$minikube start

Проверяем, что нода кластера запущена:

$ kubectl get nodes

Выполняем команду, чтобы запустить развёртывание nginx:

echo "apiVersion: apps/v1
kind: Deployment
metadata:
  name: pid-limit
  labels:
    app: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
    spec:
      volumes:
      containers:
      - name: pid-limit
        image: busybox:1.28
        command: [ "sh", "-c", "sleep 1h" ]
        ports:
        - containerPort: 80
" | kubectl apply -f -

Проверяем, что pod nginx запущен:

$ kubectl get pods

Давайте проверим лимит процессов в этом pod«е. Сначала подключимся к pod«у по SSH:
Примечание. Замените именем вашего pod«а.

$ kubectl exec -it  -- sh

Смотрим значение в /proc/sys/kernel/pid_max:

$ cat /proc/sys/kernel/pid_max    
4194304

Как видите, количество процессов практически не ограничено.

Примечание. Это значение унаследовано из того же пути в ноде Kubernetes.

Мы можем в этом убедиться, подключившись к ноде кластера Kubernetes командой minikube ssh и выполнив ту же команду cat /proc/sys/kernel/pid_max.

Часть 2. В этой части мы проверим, действительно ли большое количество процессов создаёт проблему.

Подключаемся к pod«у:

$ kubectl exec -it  -- sh

Создаём простой shell-скрипт с циклом для запуска 100 процессов. Я обычно работаю в vi, но вы можете выбрать любой редактор. Я создаю 100 процессов, чтобы показать, что число процессов в pod«е не ограничено. Вы можете указать другое число или выбрать другой способ ветвления процессов.

# vi test.sh

Этот скрипт запустит 100 процессов в фоновом режиме:

#!/bin/sh
for i in `seq 1 100`
do
    sleep 1h &
done

Сохраняем файл, добавляем разрешение на выполнение и выполняем его:

# chmod +x test.sh
# ./test.sh &

Проверяем выполняющиеся процессы:

# ps -ef

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

Запущенные процессыЗапущенные процессы

Часть3. В этой части мы изменим конфигурацию kubelet, чтобы задать лимит процессов в pod«е.

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

$ minikube ssh
$ su -
# vi /var/lib/kubelet/config.yaml

Добавляем следующую строку в конец файла, чтобы велеть kubelet запускать pod максимум с 10 процессами, и сохраняем файл:

podPidsLimit: 10

Перезапускаем сервис kubelet, чтобы применить новую конфигурацию:

# systemctl restart kubelet

Сейчас у нас два типа pod«ов:

— Выполняющиеся pod«ы, которые нужно перезапустить, чтобы к ним применилась конфигурация kubelet.

— Новые pod«ы, которые будут запущены уже с новой конфигурацией.

Перезапустим развёртывание, используя стратегию rollout:

$ kubectl rollout restart deployment/pid-limit

Подключаемся к pod«у по SSH и выполняем тот же shell-скрипт, что и раньше. Мы видим сообщение о том, что процессы больше ветвить нельзя, потому что мы достигли лимита:

7aaab6f210772396f4b61fb1a378e7bf.png

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

1483bb0f490dd85ba2fee1ac6c7fbe79.png

Заключение

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

b9ea357ef6d66b45b19935fdc6573e4b.png

Курс «Безопасность в Kubernetes» с практикой на стендах.

© Habrahabr.ru