Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Node Security Hardening for Yandex Managed Kubernetes

DaemonSet усиливает сетевую безопасность worker-узлов Yandex Managed Service for Kubernetes: ограничивает доступ к ряду служебных портов узла так, чтобы они принимали соединения только с самого узла и от подов, работающих на этом же узле, но не снаружи узла.

Применение безопасно: рабочие нагрузки не прерываются, узлы не пересоздаются.

Зачем это нужно

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

DaemonSet добавляет на узлы правила хостового фаервола, которые гарантируют, что указанные порты доступны только:

  • локально на самом узле (процессы узла, health-пробы);
  • подам, запущенным на этом узле.

TCP-обращения по IPv4, приходящие на распознанные uplink-интерфейсы узла, отклоняются — в том числе обращения с других узлов кластера и от подов, работающих на других узлах.

Что делает этот фикс

Ограничиваются порты 15100 и 15155 — до доступа только с самого узла и от подов на нём.

На каждом worker-узле кластера DaemonSet добавляет в цепочку INPUT хостового фаервола (iptables/nftables) правило на каждый host-интерфейс узла:

iptables -I INPUT 1 -i <host-iface> -p tcp -m multiport --dports 15100,15155 \
  -m addrtype ! --src-type LOCAL \
  -m comment --comment "node-security-hardening: <host-iface>" \
  -j REJECT --reject-with tcp-reset

Логика правила:

  • Обращения снаружи узла (в том числе с других узлов) — приходят на host-интерфейс, их source-адрес не является адресом самого узла (! --src-type LOCAL) → соединение отклоняется (tcp-reset).
  • Поды на этом узле — их трафик к указанным сервисам обрабатывается по внутреннему пути узла (через pod-bridge/veth), а не через host-интерфейс → доступ сохраняется.
  • Процессы самого узла (kubelet и т. п.) — их source-адрес принадлежит узлу (--src-type LOCAL) → доступ сохраняется, поэтому локальные проверки работоспособности продолжают работать.

Правило вешается на каждый host-интерфейс, распознанный по HOST_IFACE_REGEX, а не только на интерфейс маршрута по умолчанию — так покрываются узлы с несколькими сетевыми интерфейсами.

Что делает DaemonSet на каждом узле:

  1. Определяет host-интерфейсы узла.
  2. Идемпотентно устанавливает правила — перед установкой удаляет свои прежние правила, поэтому повторные запуски и обновления не создают дубликатов.
  3. Проверяет установку — убеждается, что правила присутствуют в INPUT.
  4. Мониторит состояние — раз в 5 минут (настраивается) проверяет наличие правил на всех host-интерфейсах и переустанавливает пропавшие.

Правила работают в сетевом пространстве имён хоста: DaemonSet через nsenter использует собственный бинарь iptables узла, поэтому изменения применяются к хостовому фаерволу, а не к пространству имён пода.

Быстрый старт

1. Скачать DaemonSet

wget https://raw.githubusercontent.com/yandex-cloud-examples/yc-mk8s-node-security-hardening/main/node-security-hardening-daemonset.yaml

Или клонировать репозиторий:

git clone https://github.com/yandex-cloud-examples/yc-mk8s-node-security-hardening.git
cd yc-mk8s-node-security-hardening

2. Применить

kubectl apply -f node-security-hardening-daemonset.yaml

3. Проверить статус применения

# Статус DaemonSet
kubectl get daemonset -n kube-system node-security-hardening

# На скольких узлах применено
kubectl get pods -n kube-system -l app=node-security-hardening -o wide

4. Просмотреть логи

# Логи initContainer (установка правил)
kubectl logs -n kube-system -l app=node-security-hardening -c apply

# Логи основного контейнера (мониторинг)
kubectl logs -n kube-system -l app=node-security-hardening -c monitor

Пример вывода

=========================================
node-security-hardening
Node: <node-name>
Date: <date>
=========================================
Host interfaces: eth0
Target ports:    15100,15155
Applying on eth0...
Applied rules:
-A INPUT -i eth0 -p tcp -m multiport --dports 15100,15155 -m addrtype ! --src-type LOCAL -m comment --comment "node-security-hardening: eth0" -j REJECT --reject-with tcp-reset
=========================================
Done
=========================================

Проверка

На узле — правила установлены, а локальный доступ сохранён:

# Правила присутствуют
iptables -S INPUT | grep node-security-hardening

# Локальный доступ к портам сохранён
for pt in 15100 15155; do
  timeout 3 bash -c "exec 3<>/dev/tcp/127.0.0.1/$pt" && echo "$pt local OK" || echo "$pt local BROKEN"
done

Снаружи узла — после применения соединение к этим портам по адресу узла должно отклоняться (connection reset).

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

Удаление

kubectl delete -f node-security-hardening-daemonset.yaml

Важно: удаление DaemonSet не снимает уже установленные правила фаервола — они живут в памяти ядра узла до перезагрузки узла и не сохраняются между перезагрузками (iptables-persistent не используется). Поэтому:

  • если DaemonSet удалён, а узел ещё не перезагружался — правила можно снять вручную на узле (проще удалить все свои правила по комментарию-маркеру):

    while n=$(iptables -L INPUT --line-numbers -n | awk '/node-security-hardening/{print $1; exit}'); [ -n "$n" ]; do
      iptables -D INPUT "$n"
    done
  • пока DaemonSet работает, он переустанавливает правила после перезагрузки узла автоматически.

Технические детали

Используемые разрешения:

  • hostPID: true — для входа в mount- и network-namespace хоста (PID 1) через nsenter;
  • privileged: true — для управления правилами фаервола хоста;
  • запуск бинаря iptables узла в network-namespace хоста через nsenter -t 1 -m -n.

Образ: ubuntu:22.04

Параметры (env):

  • TARGET_PORTS — порты, ограничиваемые до node-local доступа, через запятую (по умолчанию 15100,15155);
  • HOST_IFACE_REGEX — регулярка для отбора host-интерфейсов (сопоставляется с полным именем интерфейса; по умолчанию покрывает eth*, en* — физические/uplink-интерфейсы, но не pod-veth и bridge);
  • RECONCILE_INTERVAL — интервал проверки правил в секундах (по умолчанию 300).

Ресурсы:

  • Init container: 10m CPU / 32Mi RAM (requests), 100m CPU / 64Mi RAM (limits)
  • Monitor container: 5m CPU / 32Mi RAM (requests), 50m CPU / 64Mi RAM (limits)

Namespace: kube-system

Node selector: yandex.cloud/metadata-server-enabled: "true" — DaemonSet запускается на узлах с этой меткой.

Совместимость

  • ✓ Yandex Managed Service for Kubernetes
  • ✓ Ubuntu 20.04 / 22.04
  • ✓ Kubernetes 1.20+

Лицензия

Apache License 2.0

См. LICENSE для подробностей.

Поддержка

При возникновении проблем создайте issue в репозитории.

About

DaemonSet для hardening узлов Managed Kubernetes

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors