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 на каждом узле:
- Определяет host-интерфейсы узла.
- Идемпотентно устанавливает правила — перед установкой удаляет свои прежние правила, поэтому повторные запуски и обновления не создают дубликатов.
- Проверяет установку — убеждается, что правила присутствуют в
INPUT. - Мониторит состояние — раз в 5 минут (настраивается) проверяет наличие правил на всех host-интерфейсах и переустанавливает пропавшие.
Правила работают в сетевом пространстве имён хоста: DaemonSet через nsenter использует собственный бинарь iptables узла, поэтому изменения применяются к хостовому фаерволу, а не к пространству имён пода.
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-hardeningkubectl apply -f node-security-hardening-daemonset.yaml# Статус DaemonSet
kubectl get daemonset -n kube-system node-security-hardening
# На скольких узлах применено
kubectl get pods -n kube-system -l app=node-security-hardening -o wide# Логи 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 в репозитории.