Модуль 5.3: Мережеві політики
Складність:
[MEDIUM]— Важливий для безпеки, потребує розуміння селекторівЧас на виконання: 45–55 хвилин
Передумови: Модуль 5.1 (Сервіси), розуміння міток і селекторів
Що ви зможете робити
Розділ «Що ви зможете робити»Після завершення цього модуля ви зможете:
- Написати NetworkPolicies, що обмежують вхідний та вихідний трафік за допомогою селекторів Підів, просторів імен та CIDR
- Діагностувати заблокований трафік, аналізуючи правила NetworkPolicy та перевіряючи відповідність міток
- Спроєктувати мережеву позицію з типовою забороною та явними дозвільними правилами для необхідних шляхів комунікації
- Пояснити як правила NetworkPolicy комбінуються та чому порядок правил не має значення
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Типово всі поди можуть спілкуватися з усіма іншими подами. Мережеві політики дозволяють контролювати, які поди можуть звʼязуватися з якими, реалізуючи принцип найменших привілеїв для мережевого доступу. Це критично важливо для безпеки та багатоорендних кластерів.
Іспит CKAD перевіряє:
- Створення мережевих політик
- Розуміння правил вхідного (ingress) та вихідного (egress) трафіку
- Використання селекторів для вибору подів
- Зневадження проблем зі зʼєднанням
Аналогія з охороною офісної будівлі
Уявіть мережеві політики як правила охорони будівлі. Типово будівля не має охорони — будь-хто може йти куди завгодно. Мережеві політики — це як додавання зчитувачів карток. Ви визначаєте, хто може входити на які поверхи (ingress) і з яких поверхів люди можуть виходити (egress). Політика «типова заборона» — це як вимога картки для кожних дверей.
Основи мережевих політик
Розділ «Основи мережевих політик»Типова поведінка
Розділ «Типова поведінка»Без мережевих політик:
- Усі поди можуть спілкуватися з усіма подами
- Усі поди можуть досягати зовнішніх точок доступу
- Жодних обмежень
Як працюють мережеві політики
Розділ «Як працюють мережеві політики»- Мережеві політики адитивні — вони можуть лише дозволяти трафік, не забороняти
- Якщо БУДЬ-ЯКА політика вибирає під, дозволяється лише трафік, дозволений політиками
- Якщо ЖОДНА політика не вибирає під, весь трафік дозволений (типово)
- Потрібен CNI-плагін, що підтримує мережеві політики (Calico, Cilium тощо)
Базова структура
Розділ «Базова структура»apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: my-policy namespace: defaultspec: podSelector: # До яких подів застосовується ця політика matchLabels: app: my-app policyTypes: # Які типи трафіку контролювати - Ingress # Вхідний трафік - Egress # Вихідний трафік ingress: # Правила для вхідного трафіку - from: - podSelector: matchLabels: role: frontend egress: # Правила для вихідного трафіку - to: - podSelector: matchLabels: role: databaseТипи політик
Розділ «Типи політик»Ingress (вхідний трафік)
Розділ «Ingress (вхідний трафік)»Контролює, що може зʼєднуватися ДО вибраних подів:
spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080Egress (вихідний трафік)
Розділ «Egress (вихідний трафік)»Контролює, до чого вибрані поди можуть зʼєднуватися:
spec: podSelector: matchLabels: app: frontend policyTypes: - Egress egress: - to: - podSelector: matchLabels: app: backend ports: - protocol: TCP port: 8080Типи селекторів
Розділ «Типи селекторів»podSelector
Розділ «podSelector»Вибирає поди в тому ж просторі імен:
ingress:- from: - podSelector: matchLabels: role: frontendnamespaceSelector
Розділ «namespaceSelector»Вибирає поди з конкретних просторів імен:
ingress:- from: - namespaceSelector: matchLabels: env: productionКомбіновані (логіка І)
Розділ «Комбіновані (логіка І)»Під має відповідати обом селекторам:
ingress:- from: - namespaceSelector: matchLabels: env: production podSelector: # Той самий елемент списку = І matchLabels: role: frontendОкремі елементи (логіка АБО)
Розділ «Окремі елементи (логіка АБО)»Трафік дозволений від будь-якого селектора:
ingress:- from: - namespaceSelector: # Перший елемент matchLabels: env: production - podSelector: # Другий елемент = АБО matchLabels: role: frontendipBlock
Розділ «ipBlock»Вибір за діапазоном IP (зазвичай зовнішній):
ingress:- from: - ipBlock: cidr: 10.0.0.0/8 except: - 10.0.1.0/24Візуалізація
Розділ «Візуалізація»┌─────────────────────────────────────────────────────────────┐│ Концепції мережевих політик │├─────────────────────────────────────────────────────────────┤│ ││ Типово (без політики): ││ ┌─────────┐ ┌─────────┐ ┌─────────┐ ││ │ Під A │◄───►│ Під B │◄───►│ Під C │ ││ └─────────┘ └─────────┘ └─────────┘ ││ Весь трафік дозволений ││ ││ З політикою (вибрано Під B): ││ ┌─────────┐ ┌─────────┐ ┌─────────┐ ││ │ Під A │────►│ Під B │ │ Під C │ ││ │(frontend)│ │(backend)│ │(інший) │ ││ └─────────┘ └─────────┘ └─────────┘ ││ ✓ дозволено X заблоковано ││ ││ Типи селекторів: ││ ┌──────────────────────────────────────────────────┐ ││ │ │ ││ │ podSelector: Поди того ж простору імен │ ││ │ namespaceSelector: Поди з позначених просторів │ ││ │ ipBlock: Зовнішні діапазони IP │ ││ │ │ ││ │ Комбіновані в тому ж from/to елементі = І │ ││ │ Окремі from/to елементи = АБО │ ││ │ │ ││ └──────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Поширені шаблони
Розділ «Поширені шаблони»Типова заборона всього вхідного трафіку
Розділ «Типова заборона всього вхідного трафіку»Заблокувати весь вхідний трафік до подів у просторі імен:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-ingressspec: podSelector: {} # Порожній = вибрати всі поди policyTypes: - Ingress # Без правил ingress = заборонити всеТипова заборона всього вихідного трафіку
Розділ «Типова заборона всього вихідного трафіку»Заблокувати весь вихідний трафік з подів у просторі імен:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-egressspec: podSelector: {} policyTypes: - Egress # Без правил egress = заборонити всеТипова заборона всього
Розділ «Типова заборона всього»Заблокувати обидва напрямки:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-allspec: podSelector: {} policyTypes: - Ingress - EgressДозволити весь вхідний трафік
Розділ «Дозволити весь вхідний трафік»Явно дозволити все (корисно для перевизначення):
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-all-ingressspec: podSelector: {} policyTypes: - Ingress ingress: - {} # Порожнє правило = дозволити всеДозволити DNS у вихідному трафіку
Розділ «Дозволити DNS у вихідному трафіку»Необхідно при використанні типової заборони вихідного трафіку:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-dnsspec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53Повний приклад: трирівневий застосунок
Розділ «Повний приклад: трирівневий застосунок»# Фронтенд: може отримувати звідусіль, може звʼязуватися з бекендомapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: frontend-policyspec: podSelector: matchLabels: tier: frontend policyTypes: - Ingress - Egress ingress: - {} # Дозволити весь вхідний egress: - to: - podSelector: matchLabels: tier: backend ports: - port: 8080---# Бекенд: лише від фронтенду, може звʼязуватися з базою данихapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: backend-policyspec: podSelector: matchLabels: tier: backend policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: tier: frontend ports: - port: 8080 egress: - to: - podSelector: matchLabels: tier: database ports: - port: 5432---# База даних: лише від бекендуapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: database-policyspec: podSelector: matchLabels: tier: database policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: tier: backend ports: - port: 5432Швидка довідка
Розділ «Швидка довідка»# Створити мережеву політику (потрібен YAML)k apply -f policy.yaml
# Переглянути мережеві політикиk get networkpolicyk get netpol
# Описати політикуk describe netpol NAME
# Перевірити зʼєднанняk exec pod1 -- wget -qO- --timeout=2 pod2-svc:80
# Перевірити, чи CNI підтримує мережеві політикиk get pods -n kube-system | grep -E 'calico|cilium|weave'Чи знали ви?
Розділ «Чи знали ви?»-
Мережеві політики потребують сумісного CNI. Flannel не підтримує їх типово. Calico, Cilium і Weave — підтримують.
-
Політики адитивні, не субтрактивні. Ви не можете створити політику, що забороняє конкретний трафік — ви можете лише дозволяти. «Заборона» відбувається шляхом вибору пода без дозволу трафіку.
-
Порожній podSelector
{}вибирає всі поди у просторі імен. -
Коли ви вказуєте порти у вихідному трафіку, вам також може знадобитися дозволити DNS (порт 53 UDP), інакше розвʼязання імен подів не працюватиме.
Типові помилки
Розділ «Типові помилки»| Помилка | Чим це шкодить | Рішення |
|---|---|---|
| CNI не підтримує мережеві політики | Політики створені, але ігноруються | Використовуйте Calico, Cilium або Weave |
| Забули DNS у забороні вихідного | Під не може розвʼязувати імена | Додайте правило egress для kube-dns |
| Плутанина І та АБО | Вибрано не ті поди | Памʼятайте: той самий елемент=І, різні елементи=АБО |
| Плутанина з порожнім podSelector | Вибрано всі поди несподівано | {} означає «всі поди у просторі імен» |
| Забули policyTypes | Політика робить не те, що очікувалось | Завжди вказуйте Ingress та/або Egress |
Тест
Розділ «Тест»-
Що станеться з подами, які не вибрані жодною мережевою політикою?
Відповідь
Весь трафік до і від цих подів дозволений (типово відкрито). -
Як заблокувати весь вхідний трафік до подів у просторі імен?
Відповідь
Створіть політику типової заборони вхідного трафіку: ```yaml spec: podSelector: {} policyTypes: - Ingress ``` Без правил ingress весь вхідний трафік заборонений. -
Яка різниця між логікою І та АБО у селекторах мережевих політик?
Відповідь
- **І**: Селектори в тому ж елементі `from/to` (namespaceSelector + podSelector разом) - **АБО**: Окремі елементи у списку `from/to` -
Чому поди можуть не розвʼязувати DNS-імена після застосування політики типової заборони вихідного трафіку?
Відповідь
DNS-запити (порт 53 UDP) заблоковані. Потрібно явно дозволити вихідний трафік до подів kube-dns.
Практична вправа
Розділ «Практична вправа»Завдання: Реалізувати мережеву ізоляцію для простого застосунку.
Підготовка:
# Створити простір іменk create ns netpol-demo
# Створити подиk run frontend --image=nginx -n netpol-demo -l tier=frontendk run backend --image=nginx -n netpol-demo -l tier=backendk run database --image=nginx -n netpol-demo -l tier=database
# Дочекатися подівk wait --for=condition=Ready pod --all -n netpol-demo --timeout=60s
# Створити сервісиk expose pod frontend --port=80 -n netpol-demok expose pod backend --port=80 -n netpol-demok expose pod database --port=80 -n netpol-demoЧастина 1: Тест типового зʼєднання
# Усі поди можуть досягати всіх подівk exec -n netpol-demo frontend -- wget -qO- --timeout=2 backend:80k exec -n netpol-demo backend -- wget -qO- --timeout=2 database:80k exec -n netpol-demo database -- wget -qO- --timeout=2 frontend:80# Все має працюватиЧастина 2: Застосувати типову заборону
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny namespace: netpol-demospec: podSelector: {} policyTypes: - IngressEOF
# Тепер тест — все має завершитись невдачею (якщо CNI підтримує мережеві політики)k exec -n netpol-demo frontend -- wget -qO- --timeout=2 backend:80# Має завершитись тайм-аутомЧастина 3: Дозволити фронтенду доступ до бекенду
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: backend-allow-frontend namespace: netpol-demospec: podSelector: matchLabels: tier: backend policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: tier: frontend ports: - port: 80EOF
# Тестk exec -n netpol-demo frontend -- wget -qO- --timeout=2 backend:80# Має працювати
k exec -n netpol-demo database -- wget -qO- --timeout=2 backend:80# Має завершитись невдачеюПрибирання:
k delete ns netpol-demoПрактичні вправи
Розділ «Практичні вправи»Вправа 1: Типова заборона вхідного трафіку (Ціль: 2 хвилини)
Розділ «Вправа 1: Типова заборона вхідного трафіку (Ціль: 2 хвилини)»k create ns drill1k run web --image=nginx -n drill1
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: deny-ingress namespace: drill1spec: podSelector: {} policyTypes: - IngressEOF
k get netpol -n drill1k delete ns drill1Вправа 2: Дозволити конкретний під (Ціль: 3 хвилини)
Розділ «Вправа 2: Дозволити конкретний під (Ціль: 3 хвилини)»k create ns drill2k run server --image=nginx -n drill2 -l role=serverk run client --image=nginx -n drill2 -l role=clientk expose pod server --port=80 -n drill2
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-client namespace: drill2spec: podSelector: matchLabels: role: server policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: role: client ports: - port: 80EOF
k describe netpol allow-client -n drill2k delete ns drill2Вправа 3: Політика вихідного трафіку (Ціль: 3 хвилини)
Розділ «Вправа 3: Політика вихідного трафіку (Ціль: 3 хвилини)»k create ns drill3k run app --image=nginx -n drill3 -l app=webk run db --image=nginx -n drill3 -l app=dbk expose pod db --port=80 -n drill3
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: app-egress namespace: drill3spec: podSelector: matchLabels: app: web policyTypes: - Egress egress: - to: - podSelector: matchLabels: app: db ports: - port: 80EOF
k get netpol -n drill3k delete ns drill3Вправа 4: Селектор простору імен (Ціль: 3 хвилини)
Розділ «Вправа 4: Селектор простору імен (Ціль: 3 хвилини)»k create ns drill4-sourcek create ns drill4-targetk label ns drill4-source env=trusted
k run target --image=nginx -n drill4-target -l app=targetk expose pod target --port=80 -n drill4-target
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: from-trusted namespace: drill4-targetspec: podSelector: matchLabels: app: target policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: env: trustedEOF
k describe netpol from-trusted -n drill4-targetk delete ns drill4-source drill4-targetВправа 5: Комбіновані селектори (І) (Ціль: 3 хвилини)
Розділ «Вправа 5: Комбіновані селектори (І) (Ціль: 3 хвилини)»k create ns drill5k label ns drill5 env=prod
k run backend --image=nginx -n drill5 -l tier=backendk run frontend --image=nginx -n drill5 -l tier=frontend
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: combined-and namespace: drill5spec: podSelector: matchLabels: tier: backend policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: env: prod podSelector: matchLabels: tier: frontendEOF
k describe netpol combined-and -n drill5k delete ns drill5Вправа 6: Блок IP (Ціль: 3 хвилини)
Розділ «Вправа 6: Блок IP (Ціль: 3 хвилини)»k create ns drill6k run web --image=nginx -n drill6
cat << 'EOF' | k apply -f -apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: ip-block namespace: drill6spec: podSelector: {} policyTypes: - Ingress ingress: - from: - ipBlock: cidr: 10.0.0.0/8 except: - 10.0.1.0/24EOF
k describe netpol ip-block -n drill6k delete ns drill6Наступний модуль
Розділ «Наступний модуль»Сукупний тест частини 5 — Перевірте своє володіння Сервісами, Інгресом і мережевими політиками.