Перейти до вмісту

Модуль 3.4: Мережева безпека хоста

Hands-On Lab Available
K8s Cluster advanced 35 min
Launch Lab ↗

Opens in Killercoda in a new tab

Складність: [MEDIUM] - Мережеве адміністрування з фокусом на безпеку

Час на виконання: 35-40 хвилин

Передумови: Модуль 3.3 (Зміцнення ядра), базові знання мережевих технологій


Що ви зможете робити

Розділ «Що ви зможете робити»

Після завершення цього модуля ви зможете:

  • Налаштувати брандмауери на рівні хоста (iptables/nftables) для захисту портів вузлів Kubernetes
  • Аудитувати відкриті сервіси та порти вузлів на наявність непотрібної поверхні атаки
  • Реалізувати мережеву сегментацію між площиною управління, робочими вузлами та зовнішніми мережами
  • Діагностувати проблеми мережевої безпеки хоста, що обходять NetworkPolicies на рівні контейнерів

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

Хоча NetworkPolicy Kubernetes контролюють трафік між Pod, мережева безпека на рівні хоста захищає самі вузли. Відкриті порти, відкриті сервіси та нефільтрований трафік на рівні хоста можуть повністю обійти ізоляцію контейнерів.

CKS очікує, що ви розумієте як контейнерну, так і хостову мережеву безпеку.


Поверхня мережевої атаки хоста

Розділ «Поверхня мережевої атаки хоста»
┌─────────────────────────────────────────────────────────────┐
│ ПОВЕРХНЯ МЕРЕЖЕВОЇ АТАКИ ХОСТА │
├─────────────────────────────────────────────────────────────┤
│ │
│ Інтернет / Зовнішня мережа │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ХОСТ (вузол Kubernetes) │ │
│ │ │ │
│ │ Відкриті сервіси: │ │
│ │ ├── :22 SSH (управління) │ │
│ │ ├── :6443 API-сервер (площина управління) │ │
│ │ ├── :10250 API Kubelet │ │
│ │ ├── :10255 Kubelet тільки для читання │ │
│ │ │ (повинен бути вимкнений!) │ │
│ │ ├── :2379 etcd (площина управління) │ │
│ │ └── :30000-32767 Сервіси NodePort │ │
│ │ │ │
│ │ Pod з hostNetwork: true │ │
│ │ └── Має доступ до ВСІХ мережевих інтерфейсів хоста│ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ Кожен відкритий порт — потенційна точка входу │
│ ⚠️ Pod з hostNetwork обходять ізоляцію CNI │
│ │
└─────────────────────────────────────────────────────────────┘

Необхідні порти Kubernetes

Розділ «Необхідні порти Kubernetes»
┌─────────────────────────────────────────────────────────────┐
│ НЕОБХІДНІ ПОРТИ KUBERNETES │
├─────────────────────────────────────────────────────────────┤
│ │
│ Площина управління: │
│ ───────────────────────────────────────────────────────── │
│ 6443 - API-сервер Kubernetes (HTTPS) │
│ 2379 - etcd клієнт (тільки від API-сервера) │
│ 2380 - etcd peer (тільки між вузлами etcd) │
│ 10250 - API Kubelet (автентифікований) │
│ 10259 - kube-scheduler (HTTPS, localhost) │
│ 10257 - kube-controller-manager (HTTPS, localhost) │
│ │
│ Робочі вузли: │
│ ───────────────────────────────────────────────────────── │
│ 10250 - API Kubelet (автентифікований) │
│ 30000-32767 - Сервіси NodePort (якщо використовуються) │
│ │
│ Повинні бути ВИМКНЕНІ: │
│ ───────────────────────────────────────────────────────── │
│ 10255 - Порт тільки для читання Kubelet │
│ (без автентифікації!) │
│ 8080 - Небезпечний порт API-сервера (застарілий) │
│ │
└─────────────────────────────────────────────────────────────┘

Перевірка відкритих портів

Розділ «Перевірка відкритих портів»
Terminal window
# Список всіх портів, що слухають
ss -tlnp
# Список всіх портів з назвами процесів
sudo netstat -tlnp
# Перевірити конкретні порти Kubernetes
ss -tlnp | grep -E '6443|10250|2379'
# Перевірити наявність небезпечних портів
ss -tlnp | grep -E '10255|8080'
# Використання nmap з зовнішнього хоста
nmap -p 6443,10250,10255,2379 <node-ip>

Конфігурація брандмауера

Розділ «Конфігурація брандмауера»
Terminal window
# Дозволити SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Дозволити API Kubernetes (з конкретних мереж)
iptables -A INPUT -p tcp --dport 6443 -s 10.0.0.0/8 -j ACCEPT
# Дозволити API kubelet (з площини управління)
iptables -A INPUT -p tcp --dport 10250 -s 10.0.0.10/32 -j ACCEPT
# Дозволити діапазон NodePort (при потребі)
iptables -A INPUT -p tcp --dport 30000:32767 -j ACCEPT
# Заблокувати все інше
iptables -A INPUT -p tcp --dport 6443 -j DROP
iptables -A INPUT -p tcp --dport 10250 -j DROP
# Зберегти правила
iptables-save > /etc/iptables/rules.v4

Використання UFW (Ubuntu)

Розділ «Використання UFW (Ubuntu)»
Terminal window
# Увімкнити UFW
sudo ufw enable
# Дозволити SSH
sudo ufw allow ssh
# Дозволити API Kubernetes з внутрішньої мережі
sudo ufw allow from 10.0.0.0/8 to any port 6443
# Дозволити kubelet з площини управління
sudo ufw allow from 10.0.0.10 to any port 10250
# Перевірити статус
sudo ufw status verbose

Використання firewalld (RHEL/CentOS)

Розділ «Використання firewalld (RHEL/CentOS)»
Terminal window
# Дозволити API Kubernetes
sudo firewall-cmd --permanent --add-port=6443/tcp
# Дозволити kubelet
sudo firewall-cmd --permanent --add-port=10250/tcp
# Перезавантажити
sudo firewall-cmd --reload
# Перевірити відкриті порти
sudo firewall-cmd --list-ports

Вимкнення небезпечних портів

Розділ «Вимкнення небезпечних портів»

Порт тільки для читання Kubelet

Розділ «Порт тільки для читання Kubelet»
/var/lib/kubelet/config.yaml
readOnlyPort: 0 # Вимкнути порт тільки для читання (10255)
# Перезапустити kubelet
sudo systemctl restart kubelet
# Перевірити
ss -tlnp | grep 10255 # Не повинно повернути нічого

Перевірка небезпечного порту API-сервера

Розділ «Перевірка небезпечного порту API-сервера»
Terminal window
# Небезпечний порт (8080) видалено в Kubernetes 1.24+
# Для старших версій переконайтеся, що він вимкнений:
# --insecure-port=0 у прапорцях API-сервера
# Перевірити відсутність небезпечного порту
ss -tlnp | grep 8080

# hostNetwork: true обходить CNI
apiVersion: v1
kind: Pod
metadata:
name: host-network-pod
spec:
hostNetwork: true # Pod використовує мережевий простір імен вузла!
containers:
- name: app
image: nginx
# Цей Pod може:
# - Прив'язуватися до будь-якого порту на хості
# - Бачити весь мережевий трафік
# - Отримувати доступ до сервісів localhost
# - Обходити NetworkPolicy
# Використовувати Pod Security Admission для блокування
apiVersion: v1
kind: Namespace
metadata:
name: secure-ns
labels:
pod-security.kubernetes.io/enforce: restricted
# 'restricted' блокує hostNetwork: true

Контрольний список мережевого зміцнення

Розділ «Контрольний список мережевого зміцнення»
┌─────────────────────────────────────────────────────────────┐
│ КОНТРОЛЬНИЙ СПИСОК МЕРЕЖЕВОЇ БЕЗПЕКИ │
├─────────────────────────────────────────────────────────────┤
│ │
│ □ Вимкнути порт тільки для читання kubelet (10255) │
│ readOnlyPort: 0 у конфігурації kubelet │
│ │
│ □ Обмежити доступ до API-сервера │
│ Правила брандмауера для обмеження IP-адрес джерел │
│ │
│ □ Заблокувати hostNetwork для звичайних навантажень │
│ Використовувати Pod Security Admission │
│ │
│ □ Обмежити відкритість NodePort │
│ Використовувати LoadBalancer або Ingress натомість │
│ │
│ □ etcd доступний тільки від API-сервера │
│ Правила брандмауера для 2379/2380 │
│ │
│ □ Використовувати шифрування при передачі │
│ TLS для всіх компонентів │
│ │
│ □ Регулярне сканування портів │
│ Аудит на наявність несподіваних відкритих портів │
│ │
└─────────────────────────────────────────────────────────────┘

Мережеві налаштування Sysctl

Розділ «Мережеві налаштування Sysctl»
/etc/sysctl.d/99-network-security.conf
# Вимкнути ICMP-перенаправлення (запобігання MITM)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Вимкнути маршрутизацію від джерела
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Увімкнути SYN cookies (захист від SYN-флуду)
net.ipv4.tcp_syncookies = 1
# Журналювати марсіанські пакети
net.ipv4.conf.all.log_martians = 1
# Ігнорувати broadcast ICMP
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Ігнорувати помилкові повідомлення ICMP
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Застосувати
sudo sysctl -p /etc/sysctl.d/99-network-security.conf

Реальні сценарії іспиту

Розділ «Реальні сценарії іспиту»

Сценарій 1: Вимкнення порту тільки для читання Kubelet

Розділ «Сценарій 1: Вимкнення порту тільки для читання Kubelet»
Terminal window
# Перевірити, чи відкритий порт 10255
ss -tlnp | grep 10255
# Відредагувати конфігурацію kubelet
sudo vi /var/lib/kubelet/config.yaml
# Додати або змінити:
# readOnlyPort: 0
# Перезапустити kubelet
sudo systemctl restart kubelet
# Перевірити
ss -tlnp | grep 10255 # Повинно бути порожнім

Сценарій 2: Аудит відкритих портів

Розділ «Сценарій 2: Аудит відкритих портів»
Terminal window
# Список всіх портів, що слухають
ss -tlnp
# Порівняти з очікуваними портами
echo "Очікувані: 22, 6443, 10250, 10256 (kube-proxy)"
echo "Неочікувані порти слід розслідувати"
# Перевірити наявність небезпечних портів
ss -tlnp | grep -E ':10255|:8080'

Сценарій 3: Налаштування брандмауера

Розділ «Сценарій 3: Налаштування брандмауера»
Terminal window
# Заблокувати зовнішній доступ до kubelet
sudo iptables -A INPUT -p tcp --dport 10250 ! -s 10.0.0.0/8 -j DROP
# Дозволити тільки площині управління доступ до kubelet
sudo iptables -I INPUT -p tcp --dport 10250 -s 10.0.0.10 -j ACCEPT
# Перевірити
sudo iptables -L INPUT -n | grep 10250

Захист мережевого доступу до etcd

Розділ «Захист мережевого доступу до etcd»
Terminal window
# etcd повинен приймати з'єднання тільки від API-сервера
# На вузлі etcd:
sudo iptables -A INPUT -p tcp --dport 2379 -s <api-server-ip> -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2379 -j DROP
# Для peer-трафіку etcd (багатовузловий etcd)
sudo iptables -A INPUT -p tcp --dport 2380 -s <etcd-node-1-ip> -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2380 -s <etcd-node-2-ip> -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2380 -j DROP

  • Порт тільки для читання kubelet (10255) надає інформацію про Pod без автентифікації. Він був корисним для налагодження, але є ризиком безпеки. Сучасний Kubernetes використовує автентифіковані точки доступу метрик.

  • Хмарні провайдери часто керують правилами брандмауера через Security Groups (AWS), Firewall Rules (GCP) або Network Security Groups (Azure). Вони доповнюють брандмауери на рівні хоста.

  • Сервіси NodePort відкриваються на всіх вузлах, навіть якщо Pod працює лише на одному. Це збільшує поверхню атаки. Використовуйте LoadBalancer або Ingress для обмеження відкритості.

  • Плагіни CNI забезпечують ізоляцію мережі Pod, але Pod з hostNetwork повністю обходять це, працюючи безпосередньо в мережевому стеку хоста.


ПомилкаЧому це шкодитьРішення
Залишити 10255 відкритимВитік інформації без автентифікаціїВстановити readOnlyPort: 0
Без брандмауера хостаВсі порти відкритіНалаштувати iptables/ufw
Використання NodePort публічноКожен вузол — точка входуВикористовуйте LoadBalancer/Ingress
Дозвіл hostNetworkОбхід ізоляції мережіБлокувати з PSA
etcd відкритий для кластераДані можуть бути викраденіОбмежити до API-сервера

  1. Що таке порт тільки для читання kubelet і чому його слід вимкнути?

    Відповідь Порт 10255 надає інформацію про Pod без автентифікації. Зловмисники можуть перелічити Pod, контейнери та їхні конфігурації. Вимкніть за допомогою `readOnlyPort: 0` у конфігурації kubelet.
  2. Які Pod обходять NetworkPolicy Kubernetes?

    Відповідь Pod з `hostNetwork: true` обходять NetworkPolicy, оскільки вони використовують мережевий простір імен хоста безпосередньо замість мережі Pod, керованої CNI.
  3. Які порти використовує etcd і хто повинен мати до них доступ?

    Відповідь Порт 2379 для клієнтських з'єднань (тільки API-сервер повинен мати доступ) та 2380 для peer-з'єднань (тільки інші вузли etcd). Обидва повинні бути захищені брандмауером.
  4. Як перевірити, що небезпечні порти вимкнені?

    Відповідь Використовуйте `ss -tlnp | grep -E '10255|8080'`, щоб перевірити, чи слухають ці порти. Порожній вивід означає, що вони вимкнені.

Завдання: Аудит та захист мережевої конфігурації вузла.

Terminal window
# Крок 1: Перевірити всі відкриті порти
echo "=== Відкриті порти ==="
ss -tlnp
# Крок 2: Перевірити наявність небезпечних портів
echo "=== Перевірка небезпечних портів ==="
ss -tlnp | grep -E ':10255|:8080' && echo "ПОПЕРЕДЖЕННЯ: Відкриті небезпечні порти!" || echo "OK: Небезпечних портів немає"
# Крок 3: Перевірити конфігурацію порту тільки для читання kubelet
echo "=== Конфігурація Kubelet ==="
grep -i readOnlyPort /var/lib/kubelet/config.yaml 2>/dev/null || echo "Перевірте на реальному вузлі"
# Крок 4: Перевірити мережеві налаштування sysctl
echo "=== Мережеві налаштування безпеки Sysctl ==="
sysctl net.ipv4.conf.all.accept_redirects
sysctl net.ipv4.conf.all.send_redirects
sysctl net.ipv4.tcp_syncookies
# Крок 5: Список поточних правил брандмауера (якщо є)
echo "=== Правила брандмауера ==="
sudo iptables -L INPUT -n --line-numbers 2>/dev/null | head -20 || echo "Перевірте iptables на реальному вузлі"
# Крок 6: Перевірити наявність Pod з hostNetwork
echo "=== Pod з hostNetwork ==="
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.hostNetwork==true) | "\(.metadata.namespace)/\(.metadata.name)"'
# Критерії успіху:
# - Немає відкритих небезпечних портів
# - readOnlyPort: 0 у конфігурації kubelet
# - Мінімум Pod, що використовують hostNetwork

Критерії успіху: Виявити проблеми безпеки та знати, як їх усунути.


Необхідні порти:

  • 6443: API-сервер
  • 10250: Kubelet (автентифікований)
  • 2379/2380: etcd (обмежений)

Вимкнути ці порти:

  • 10255: Kubelet тільки для читання
  • 8080: Небезпечний порт API

Стратегія брандмауера:

  • Дозволяти тільки необхідні порти
  • Обмежувати IP-адреси джерел
  • Блокувати hostNetwork для навантажень

Поради для іспиту:

  • Знайте, як перевірити відкриті порти
  • Вмійте вимкнути порт тільки для читання kubelet
  • Розумійте ризики hostNetwork

Частина 3 завершена!

Розділ «Частина 3 завершена!»

Ви закінчили Зміцнення системи (15% CKS). Тепер ви розумієте:

  • Профілі AppArmor для контейнерів
  • Фільтрацію системних викликів Seccomp
  • Зміцнення ядра Linux та ОС
  • Мережеву безпеку хоста

Наступна частина: Частина 4: Мінімізація вразливостей мікросервісів — Контексти безпеки, Pod Security та управління секретами.