Введення в мережеві політики Kubernetes для фахівців з безпеки

Введення в мережеві політики Kubernetes для фахівців з безпеки

Прим. перев.: Автор статті — Reuven Harrison — має понад 20 років досвіду у розробці програмного забезпечення, а на сьогоднішній день є технічним директором та співзасновником компанії Tufin, яка створює рішення для управління політиками безпеки. Розглядаючи мережеві політики Kubernetes як досить потужний засіб для сегментації мережі в кластері, він у той же час вважає, що вони не такі прості у застосуванні на практиці. Даний матеріал (досить об'ємний) покликаний покращити обізнаність фахівців у цьому питанні та допомогти їм у створенні необхідних конфігурацій.

Сьогодні багато компаній все частіше вибирають Kubernetes для запуску своїх програм. Інтерес до цього програмного забезпечення настільки високий, що деякі називають Kubernetes «новою операційною системою для центрів обробки даних». Поступово Kubernetes (або k8s) починає сприйматися як критично важлива частина бізнесу, яка потребує організації зрілих бізнес-процесів, у тому числі забезпечення безпеки мережі.

Для фахівців з безпеки, яких спантеличили роботою з Kubernetes, справжнім відкриттям може стати політика цієї платформи за умовчанням: дозволити все.

Цей посібник допоможе розібратися у внутрішньому пристрої мережевих політик; зрозуміти, чим вони відрізняються від правил для звичайних брандмауерів. Також буде розказано про деякі підводні камені та будуть надані рекомендації, які допоможуть захистити програми в Kubernetes.

Мережеві політики Kubernetes

Механізм мережевих політик Kubernetes дозволяє керувати взаємодією розгорнутих на платформі додатків на мережевому рівні (третій у моделі OSI). Мережеві політики позбавлені деяких передових функцій сучасних брандмауерів, таких як контроль на 7 рівні OSI та виявлення загроз, проте вони забезпечують базовий рівень мережевої безпеки, який є непоганою відправною точкою.

Мережеві політики контролюють комунікації між pod'ами

Робочі навантаження в Kubernetes розподіляються по pod'ах, які складаються з одного або кількох контейнерів, розгорнутих спільно. Kubernetes надає кожному pod'у IP-адресу, доступну з інших pod'ів. Мережеві політики Kubernetes задають права доступу для груп pod'ів так само, як групи безпеки в хмарі використовуються для керування доступом до екземплярів віртуальних машин.

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

Як і інші ресурси Kubernetes, мережні політики задаються мовою YAML. У наведеному нижче прикладі додатку balance відкривається доступ до postgres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: balance
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

(Прим. перев.: цей скріншот, як і всі наступні аналогічні, створено не рідними засобами Kubernetes, а за допомогою інструменту Tufin Orca, за розробкою якого стоїть компанія автора оригінальної статті і згадується в кінці матеріалу.)

Для визначення власної мережевої політики знадобляться базові знання YAML. Ця мова ґрунтується на відступах (що задаються пробілами, а не табуляцією). Елемент із відступом належить найближчому елементу з відступом над ним. Новий елемент списку починається з дефісу, всі інші елементи мають вигляд ключ-значення.

Описавши політику на YAML, використовуйте кубектл, щоб створити її в кластері:

kubectl create -f policy.yaml

Специфікація мережевої політики

Специфікація мережевої політики Kubernetes включає чотири елементи:

  1. podSelector: визначає pod'и, що торкаються цієї політики (мети) - обов'язковий;
  2. policyTypes: вказує, які типи політик включені до цієї: ingress та/або egress — необов'язковий, проте я рекомендую його явно прописувати у всіх випадках;
  3. ingress: визначає дозволений що входить трафік у цільові pod'и – необов'язковий;
  4. egress: визначає дозволений вихідний трафік із цільових pod'ів — необов'язковий.

Приклад, запозичений із сайту Kubernetes (я замінив role на app), показує, як використовуються всі чотири елементи:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:    # <<<
    matchLabels:
      app: db
  policyTypes:    # <<<
  - Ingress
  - Egress
  ingress:        # <<<
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:         # <<<
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Введення в мережеві політики Kubernetes для фахівців з безпеки
Введення в мережеві політики Kubernetes для фахівців з безпеки

Зауважте, що всі чотири елементи включати необов'язково. Обов'язковим є лише podSelectorІнші параметри можна використовувати за бажанням.

Якщо опустити policyTypes, політика інтерпретуватиметься так:

  • За умовчанням передбачається, що вона визначає ingress-сторону. Якщо явних вказівок щодо цього у політиці не міститься, система вважатиме, що весь трафік заборонено.
  • Поведінка на egress-стороні визначатиметься наявністю або відсутністю відповідного egress-параметра.

Щоб уникнути помилок, я рекомендую завжди явно вказувати policyTypes.

Відповідно до наведеної вище логіки у випадку, якщо параметри ingress і / або egress опущені, політика заборонятиме весь трафік (див. «Правило зачистки» нижче).

За замовчуванням — дозволити

Якщо політики не визначені, Kubernetes за промовчанням дозволяє весь трафік. Усі pod'и вільно можуть обмінюватися інформацією між собою. З точки зору безпеки це може здатися нелогічним, але згадайте про те, що Kubernetes спочатку створювався розробниками для забезпечення взаємодії додатків. Мережеві політики було додано пізніше.

Простір імен

Простір імен (Namespaces) - механізм колективної роботи Kubernetes. Вони призначені для ізолювання логічних оточень друг від друга, у своїй обмін даними між просторами за умовчанням дозволено.

Як і більшість компонентів Kubernetes, мережеві політики мешкають у певному просторі імен. У блоці metadata можна прописати, якому саме простору належить політика:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace  # <<<
spec:
...

Якщо простір імен у метаданих явно не прописано, система використовуватиме namespace, вказане в kubectl (за замовчуванням namespace=default):

kubectl apply -n my-namespace -f namespace.yaml

Я рекомендую явно вказувати namespace, якщо ви не пишете політику, призначену відразу кількох просторів імен.

Основний елемент podSelector у політиці обиратиме pod'и з простору імен, до якого належить політика (він позбавлений доступу до pod'ів з іншого простору імен).

Аналогічним чином podSelector'и у блоках ingress та egress можуть вибирати pod'и тільки зі свого простору імен, якщо, звичайно, ви не поєднаєте їх за допомогою namespaceSelector (про це йтиметься у розділі «Фільтр за просторами імен та pod'ам»).

Правила іменування політик

Назви політика унікальні в рамках одного простору імен. Двох політик з однаковою назвою в одному просторі не може бути, але можуть бути політики з однаковими назвами в різних просторах. Це зручно, коли ви хочете повторно застосувати ту саму політику на кількох просторах.

Мені особливо подобається один із способів іменування. Він полягає в тому, щоб поєднувати назву простору імен із цільовими pod'ами. Наприклад:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres  # <<<
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Лейбли

До об'єктів Kubernetes, таких як pod'и та простору імен, можна прикріплювати лейбле користувача. Лейбли (етикетки - Мітки) є еквівалентом тегів у хмарі. Мережеві політики Kubernetes використовують лейбли для вибору pod'ів, до яких вони застосовуються:

podSelector:
  matchLabels:
    role: db

... або просторів імендо яких вони застосовуються. У цьому прикладі вибираються всі pod'и у просторах імен з відповідними лейблами:

namespaceSelector:
  matchLabels:
    project: myproject

Одна застереження: при використанні namespaceSelector переконайтеся, що вибрані простору імен містять у собі потрібний лейбл. Майте на увазі, що вбудовані простори імен, такі як default и kube-system, за замовчуванням не містять лейблів.

Додати лейбл до простору можна так:

kubectl label namespace default namespace=default

При цьому namespace у розділі metadata повинен посилатися на фактичне ім'я простору, а не на лейбл:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default   # <<<
spec:
...

Джерело та адресат

Політики для брандмауерів складаються з правил із джерелами та адресатами. Мережеві політики Kubernetes визначаються для мети - набору з pod'ів, до яких вони застосовуються, а потім встановлюють правила для вхідного (ingress) та/або вихідного (egress) трафіку. У нашому прикладі метою політики будуть усі pod'и у просторі імен default з лейблом із ключем app та значенням db:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: db   # <<<
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Введення в мережеві політики Kubernetes для фахівців з безпеки
Введення в мережеві політики Kubernetes для фахівців з безпеки

підрозділ ingress у цій політиці відкриває вхідний трафік до цільових pod'ів. Інакше кажучи, ingress виступає джерелом, а ціль — відповідним адресатом. Аналогічним чином egress є адресатом, а мета його джерелом.

Введення в мережеві політики Kubernetes для фахівців з безпеки

Це еквівалентно двом правилам для брандмауера: Ingress → Мета; Мета → Egress.

Egress та DNS (важливо!)

Обмежуючи вихідний трафік, особливу увагу зверніть на DNS — Kubernetes використовує цю службу зіставлення сервісів з IP-адресами. Наприклад, наступна політика не спрацює, оскільки ви не дозволили застосуванню balance звертатися до DNS:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  policyTypes:
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Виправити її можна, відкривши доступ до сервісу DNS:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:               # <<<
    ports:            # <<<
    - protocol: UDP   # <<<
      port: 53        # <<<
  policyTypes:
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Останній елемент to — порожній, і тому він опосередковано вибирає всі pod'и у всіх просторах імендозволяючи balance посилати DNS-запити до відповідної служби Kubernetes (зазвичай вона працює у просторі kube-system).

Цей підхід працює, проте він надмірно вирішальний та небезпечний, оскільки дозволяє спрямовувати DNS-запити за межі кластера.

Поліпшити його можна трьома послідовними кроками.

1. Дозволити DNS-запити тільки всередині кластера, додавши namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector: {} # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки

2. Дозволити DNS-запити лише у просторі імен kube-system.

Для цього потрібно додати лейбл у простір імен kube-system: kubectl label namespace kube-system namespace=kube-system - І прописати її в політиці за допомогою namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector:         # <<<
        matchLabels:             # <<<
          namespace: kube-system # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки

3. Параноїки можуть піти ще далі і обмежити DNS-запити певною DNS-службою kube-system. У розділі «Фільтр за просторами імен І pod'ам» буде розказано, як цього досягти.

Інший варіант - дозволити DNS лише на рівні простору імен. У цьому випадку його не потрібно буде відкривати для кожної служби:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.dns
  namespace: default
spec:
  podSelector: {} # <<<
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

порожній podSelector вибирає всі pod'и у просторі імен.

Введення в мережеві політики Kubernetes для фахівців з безпеки

Перша відповідність та порядок правил

У звичайних брандмауерах дія ("Дозволити" або "Заборонити") щодо пакета визначається першим правилом, якому він задовольняє. У Kubernetes порядок політик не має жодного значення.

За замовчуванням, коли політики не задані, комунікації між pod'ами дозволені і можуть вільно обмінюватися інформацією. Як тільки ви починаєте формулювати політики, кожен pod, порушений хоча б однією з них, стає ізольованим відповідно до диз'юнкції (логічним АБО) всіх політиків, які його обрали. Pod'и, не порушені будь-якою політикою, залишаються відкритими.

Змінити таку поведінку можна за допомогою правила зачистки.

Правило зачистки («Заборонити»)

Політики брандмауерів зазвичай забороняють будь-який явно не дозволений трафік.

У Kubernetes немає дії "заборонити" (deny), однак аналогічного ефекту можна досягти зі звичайною (дозволяючою) політикою, вибравши порожню групу pod'ів-джерел (ingress):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Ця політика вибирає всі pod'и у просторі імен та залишає ingress невизначеним, забороняючи весь вхідний трафік.

Подібним чином можна обмежити весь вихідний трафік із простору імен:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Врахуйте, що будь-які додаткові політики, що дозволяють трафік до pod'ів у просторі імен, матимуть пріоритет над цим правилом (аналогічно доданню дозволяючого правила перед брандмауера, що забороняє в конфігурації).

Дозволити все (Any-Any-Any-Allow)

Щоб створити політику «Дозволити все», необхідно доповнити наведену вище заборонну політику порожнім елементом ingress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  podSelector: {}
  ingress: # <<<
  - {}     # <<<
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Вона відкриває доступ зі всіх pod'ів у всіх просторах імен (і всіх IP) до будь-якого pod'у у просторі імен default. Така поведінка включена за умовчанням, тому зазвичай її не потрібно визначати додатково. Однак іноді може знадобитися тимчасово відключити деякі конкретні дозволи для діагностики проблеми.

Правило можна звузити та дозволити доступ тільки до певному набору pod'ів (app:balance) у просторі імен default:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-to-balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  ingress: 
  - {}
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Наступна політика дозволяє весь вхідний (ingress) і вихідний (egress) трафік, включаючи доступ до будь-якого IP за межами кластера:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}
  egress:
  - {}
  policyTypes:
  - Ingress
  - Egress

Введення в мережеві політики Kubernetes для фахівців з безпеки
Введення в мережеві політики Kubernetes для фахівців з безпеки

Об'єднання кількох політик

Політики об'єднуються за допомогою логічного АБО на трьох рівнях; дозволи кожного pod'а встановлюються відповідно до диз'юнкції всіх політик, які його зачіпають:

1. У полях from и to можна визначити три типи елементів (усі вони комбінуються за допомогою АБО):

  • namespaceSelector - Вибирає простір імен цілком;
  • podSelector - Вибирає pod'и;
  • ipBlock - Вибирає підсіти.

При цьому кількість елементів (навіть однакових) у підрозділах from/to НЕ обмежено. Усі вони будуть об'єднані логічним АБО.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

2. Усередині політики розділ ingress може мати безліч елементів from (Об'єднуються логічним АБО). Аналогічно розділ egress може включати безліч елементів to (також об'єднуються диз'юнкцією):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
  - from:
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

3. Різні політики також об'єднуються логічним АБО

Але при їх об'єднанні існує одне обмеження, на яке вказав Chris Cooney: Kubernetes може комбінувати політики тільки з різними policyTypes (Ingress або Egress). Політики, що визначають ingress (або egress), перезапишуть один одного.

Зв'язок між просторами імен

За промовчанням обмін інформацією між просторами імен дозволено. Змінити це можна за допомогою заборонної політики, яка обмежить вихідний та/або вхідний трафік у простір імен (див. «Правило зачистки» вище).

Заблокувавши доступ до простору імен (див. «Правило зачистки» вище), ви можете внести винятки в заборонну політику, дозволивши підключення з певного простору імен за допомогою namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: # <<<
        matchLabels:
          namespace: default
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

В результаті всі pod'и у просторі імен default отримають доступ до pod'ів postgres у просторі імен database. Але що, якщо ви хочете відкрити доступ до postgres тільки конкретним pod'ам у просторі імен default?

Фільтр за просторами імен І pod'ам

Kubernetes версії 1.11 та вище дозволяє комбінувати оператори namespaceSelector и podSelector за допомогою логічного І. Виглядає це так:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          namespace: default
      podSelector: # <<<
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Чому це трактується як І замість звичного АБО?

Зверніть увагу, що podSelector не починається з дефісу. У YAML це означає, що podSelector і стоїть перед ним namespaceSelector відносяться до того самого елемента списку. Тому вони поєднуються логічним І.І.

Додавання дефісу перед podSelector призведе до виникнення нового елемента списку, який комбінуватиметься з попереднім namespaceSelector за допомогою логічного АБО.

Щоб вибрати pod'и з певним лейблом у всіх просторах імен, впишіть порожній namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Множинні лейбли об'єднуються з І

Правила для брандмауера з багатьма об'єктами (хостами, мережами, групами) комбінуються за допомогою логічного АБО. Наступне правило спрацює, якщо джерело пакету збігається з Host_1 АБО Host_2:

| Source | Destination | Service | Action |
| ----------------------------------------|
| Host_1 | Subnet_A    | HTTPS   | Allow  |
| Host_2 |             |         |        |
| ----------------------------------------|

Навпаки, у Kubernetes різні лейбли в podSelector або namespaceSelector поєднуються логічним І. Наприклад, наступне правило вибере pod'и, що володіють обома лейблами, role=db И version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

Та ж логіка застосовується до всіх типів операторів: селекторів цілей політики, селекторів pod'ів та селекторів просторів імен.

Підмережі та IP-адреси (IPBlocks)

Для сегментування мережі брандмауери використовують VLAN, IP-адреси та підмережі.

У Kubernetes IP-адреси присвоюються pod'ам автоматично і можуть часто змінюватися, тому для вибору pod'ів і просторів імен у мережевих політиках використовуються лейбли.

Підмережі (ipBlocks) використовуються при керуванні вхідними (ingress) або вихідними (egress) зовнішніми (North-South) підключеннями. Наприклад, ця політика відкриває всім pod'ам з простору імен default доступ до DNS-сервісу Google:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 8.8.8.8/32
    ports:
    - protocol: UDP
      port: 53

Введення в мережеві політики Kubernetes для фахівців з безпеки

Порожній селектор pod'ів у цьому прикладі означає «вибрати всі pod'и у просторі імен».

Ця політика відкриває доступ лише до 8.8.8.8; доступ до будь-якого іншого IP заборонено. Таким чином, ви заблокували доступ до внутрішньої служби DNS Kubernetes. Якщо ви все ж таки хочете його відкрити, вкажіть це явно.

Зазвичай ipBlocks и podSelectors є взаємовиключними, оскільки внутрішні IP-адреси pod'ів не використовуються в ipBlocks. Вказавши внутрішні IP pod'ів, Ви фактично дозволите підключення до/від pod'ів з цими адресами. На практиці ви не знатимете, яку IP-адресу використовувати, саме тому їх не варто застосовувати для вибору pod'ів.

Як контр-приклад наступна політика включає всі IP і, отже, дозволяє доступ до всіх інших pod'ам:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0

Введення в мережеві політики Kubernetes для фахівців з безпеки

Можна відкрити доступ лише до зовнішніх IP, виключивши внутрішні IP-адреси pod'ів. Наприклад, якщо підсіти вашого pod'а 10.16.0.0/14:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.16.0.0/14

Введення в мережеві політики Kubernetes для фахівців з безпеки

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

Зазвичай pod'и слухають один порт. Це означає, що можна просто не вказувати номери портів у політиках та залишити все за замовчуванням. Втім, політики рекомендується робити максимально обмежувальними, тому в деяких випадках все ж таки можна вказувати порти:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
      - port: 443      # <<<
        protocol: TCP  # <<<
      - port: 80       # <<<
        protocol: TCP  # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Зауважте, що селектор ports застосовується до всіх елементів у блоці to або from, В якому міститься. Щоб вказати різні порти для різних наборів елементів, розбийте ingress або egress на кілька підрозділів з to або from і в кожному пропишіть свої порти:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    ports:             # <<<
     - port: 443       # <<<
       protocol: TCP   # <<<
  - from:
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
     - port: 80        # <<<
       protocol: TCP   # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Введення в мережеві політики Kubernetes для фахівців з безпеки

Робота портів за замовчуванням:

  • Якщо ви повністю опускаєте визначення портів (ports), це означає всі протоколи та всі порти;
  • Якщо ви опускаєте визначення протоколу (protocol), це означає TCP;
  • Якщо ви опускаєте визначення порту (port), це означає всі порти.

Найкраща практика: не покладайтеся на значення за промовчанням, вказуйте потрібне вам явно.

Зверніть увагу, що необхідно використовувати порти pod'ів, а не сервісів (докладніше про це у наступному параграфі).

Політики визначені для pod'ів чи сервісів?

Зазвичай pod'и в Kubernetes звертаються один до одного через сервіс - віртуальний балансувальник навантаження, що перенаправляє трафік до pod'ів, що реалізує сервіс. Можна подумати, що мережеві політики контролюють доступом до сервісів, але це негаразд. Мережеві політики Kubernetes працюють із портами pod'ів, а не сервісів.

Наприклад, якщо сервіс слухає 80-й порт, але перенаправляє трафік на порт 8080 своїх pod'ів, у мережевій політиці необхідно вказати саме 8080.

Подібний механізм слід визнати неоптимальним: за зміни внутрішнього пристрою сервісу (порти якого слухають pod'и) доведеться оновлювати мережеві політики.

Новий архітектурний підхід із використанням Service Mesh (наприклад, див. про Istio нижче - прим. перекл.) дозволяє впоратися із цією проблемою.

Чи потрібно прописувати як Ingress, так і Egress?

Коротка відповідь - так, щоб pod А міг зв'язатися з pod'ом В, необхідно дозволити йому створювати вихідне з'єднання (для цього слід налаштувати egress-політику), а pod повинен мати можливість приймати вхідне з'єднання (для цього, відповідно, потрібна ingress- політика).

Однак на практиці можна покластися на політику за умовчанням, що дозволяє з'єднання в одному або обох напрямках.

Якщо якийсь pod-джерело буде обрано однією або декількома вихід-Політиками, що накладаються на нього обмеження будуть визначатися їх диз'юнкцією. У цьому випадку потрібно явно дозволити підключення до pod'у-адресату. Якщо pod не вибрано будь-якої політики, його вихідний (egress) трафік дозволено за замовчуванням.

Аналогічно доля pod'а-адресата, обраного однією або декількома проникнення-Політиками, визначатиметься їх диз'юнкцією. В цьому випадку необхідно явно дозволити йому отримувати трафік від pod'а-джерела. Якщо pod не вибраний будь-якою політикою, весь вхідний трафік для нього дозволений за замовчуванням.

Див. «Stateful або Stateless» нижче.

Список

Мережеві політики Kubernetes не можуть журналювати трафік. Це ускладнює визначення того, чи працює політика належним чином, і сильно ускладнює аналіз безпеки.

Контроль за трафіком до зовнішніх сервісів

Мережеві політики Kubernetes не дозволяють вказувати повноцінне доменне ім'я (DNS) у розділах egress. Цей факт призводить до значної незручності при спробі обмежити трафік до зовнішніх адресатів, позбавлених фіксованої IP-адреси (наприклад, aws.com).

Перевірка політики

Брандмауери попередять вас або навіть відмовляться ухвалити помилкову політику. Kubernetes також проводить певну верифікацію. При заданні мережевої політики через Kubectl Kubernetes може заявити, що вона неправильна, і відмовитися її прийняти. В інших випадках Kubernetes прийме політику і доповнить її деталями, що бракують. Їх можна побачити за допомогою команди:

kubernetes get networkpolicy <policy-name> -o yaml

Майте на увазі, що система перевірки Kubernetes є непохитною і може пропускати деякі типи помилок.

Виконання

Kubernetes не займається реалізацією мережевих політик самостійно, а є лише API-шлюзом, що покладає обтяжливу роботу з контролю на систему, що нижче лежить, звану Container Networking Interface (CNI). Завдання політик у кластері Kubernetes без призначення відповідного CNI аналогічно до створення політик на сервері управління брандмауером без їх подальшої установки в брандмауери. Ви самі повинні переконатися у наявності гідного CNI або, у випадку платформ Kubernetes, розміщених у хмарі (Зі списком провайдерів можна ознайомитися тут - прим. пров.), задіяти мережеві політики, які встановлять CNI для вас.

Зверніть увагу, що Kubernetes не попередить вас, якщо ви поставите мережну політику без відповідного допоміжного CNI.

Stateful чи Stateless?

Всі CNI Kubernetes, з якими мені доводилося зіштовхуватися, зберігають стани (наприклад, Calico використовує Linux conntrack). Це дозволяє pod'у отримувати відповіді щодо ініційованого ним TCP-з'єднання без необхідності встановлювати його заново. При цьому мені невідомо про стандарт Kubernetes, який би гарантував зберігання стану (statefulness).

Просунуте управління політикою безпеки

Ось кілька способів підвищити ефективність виконання політики безпеки в Kubernetes:

  1. Архітектурний патерн Service Mesh використовує sidecar-контейнери для забезпечення детальної телеметрії та контролю за трафіком на рівні сервісів. Як приклад можна взяти Істіо.
  2. Деякі з постачальників CNI доповнили свої інструменти, щоб ті вийшли за межі мережевих політик Kubernetes.
  3. Tufin Orca забезпечує прозорість та автоматизацію мережевих політик Kubernetes.

Пакет Tufin Orca керує мережевими політиками Kubernetes (і є джерелом скріншотів, наведених вище).

Додаткова інформація

Висновок

Мережеві політики Kubernetes пропонують непоганий набір інструментів для сегментації кластерів, проте вони інтуїтивно незрозумілі та мають безліч тонкощів. Я вважаю, що через цю складність політики багатьох кластерів містять помилки. Можливими рішеннями цієї проблеми є автоматизація визначень політик чи застосування інших засобів сегментації.

Сподіваюся, що цей посібник допоможе прояснити деякі питання та вирішити проблеми, з якими ви можете зіткнутися.

PS від перекладача

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук