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

Модуль 3.1: Безпека Подів

Складність: [СЕРЕДНЯ] — базові знання для інженерів, яким потрібно оцінювати ризики під час виконання Подів та поведінку допуску

Час на проходження: 40–50 хвилин читання, перегляду маніфестів і практичної роботи з усунення проблем

Передумови: Модуль 2.4: PKI та сертифікати, а також базова впевненість у читанні YAML Подів і міток просторів імен

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

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

Після завершення цього модуля ви зможете переглядати реальні маніфести Подів, діагностувати поведінку Pod Security Admission та пояснювати компроміси безпеки, що стоять за кожною рекомендованою зміною:

  1. Оцінювати налаштування securityContext на рівні Пода й контейнера, щоб відокремити прийнятні рішення з посилення безпеки від конфігурацій, що уможливлюють підвищення привілеїв, доступ до хоста чи закріплення зловмисника.
  2. Порівнювати профілі Pod Security Standards privileged, baseline та restricted і рекомендувати найменш дозвільний профіль, що підходить для класу робочого навантаження.
  3. Діагностувати відмови та попередження Pod Security Admission, зіставляючи відповідь API з точним полем, що порушує політику простору імен.
  4. Проєктувати посилену специфікацію Пода, яка працює не від імені root, відкидає непотрібні можливості Linux, використовує seccomp і зберігає працездатність застосунку завдяки явно заданим шляхам для запису.
  5. Визначати, коли виняток для робочого навантаження виправданий, а потім обмежувати цей виняток мітками простору імен, ізоляцією навантаження та задокументованими компенсувальними засобами контролю.

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

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

Платформена команда успадковує кластер, де кожен простір імен застосунків дозволяє привілейовані Поди, бо одному агенту моніторингу багато років тому знадобився доступ до хоста. Через місяці вразливий вебзастосунок зазнає компрометації, і зловмисник виявляє, що контейнер може працювати від імені root, додавати широкі можливості Linux, писати у свою файлову систему та спільно використовувати мережу вузла. Початкова помилка застосунку була звичайною; радіус ураження став небезпечним, бо Поду дозволили поводитися як частина хоста.

Безпека Подів — це межа між «зловмисник контролює один процес» і «зловмисник може взаємодіяти з вузлом». Kubernetes не робить кожен Под безпечним за замовчуванням, бо багатьом легітимним системним компонентам потрібен потужний доступ до мережі, пристроїв чи просторів імен хоста. Така гнучкість корисна для операторів кластера, але це означає, що командам застосунків доводиться вчитися розрізняти, які поля є рутинним посиленням безпеки, які поля є винятками, а які поля мають запускати перегляд дизайну.

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

Цей модуль навчає безпеки Подів як процесу прийняття рішень, а не як контрольного списку. Спершу ви побудуєте ментальну модель того, де застосовуються засоби контролю Подів, потім дослідите поширені небезпечні поля, а далі пов’яжете ці поля з Pod Security Standards та Pod Security Admission. Наприкінці ви маєте вміти подивитися на маніфест Пода й пояснити не лише те, чи він дозволений, а й чому існує ризик і як його зменшити, не зламавши робоче навантаження.

Безпека Подів починається з меж

Розділ «Безпека Подів починається з меж»

Контейнер ізольовано засобами ядра Linux, такими як простори імен, cgroups, можливості (capabilities) та фільтри seccomp. Kubernetes надає багато цих засобів контролю через специфікацію Пода, тож команди можуть вирішувати, наскільки робочому навантаженню дозволено бачити хост чи впливати на нього. Важлива ідея полягає в тому, що безпека Пода — це не один перемикач; це набір рівнів, які або зберігають, або послаблюють ізоляцію.

┌───────────────────────────────────────────────────────────────┐
│ POD SECURITY LAYERS │
├───────────────────────────────────────────────────────────────┤
│ │
│ POD-LEVEL SETTINGS │
│ Apply to the whole pod unless a container overrides them │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ securityContext: │ │
│ │ runAsUser, runAsGroup, fsGroup │ │
│ │ seccompProfile │ │
│ │ hostNetwork, hostPID, hostIPC │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ CONTAINER-LEVEL SETTINGS │
│ Apply to one container and can be more specific │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ securityContext: │ │
│ │ runAsUser, runAsNonRoot │ │
│ │ readOnlyRootFilesystem │ │
│ │ allowPrivilegeEscalation │ │
│ │ capabilities, privileged, seccompProfile │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ADMISSION ENFORCEMENT │
│ Decides whether the API server accepts the pod │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Pod Security Standards │ │
│ │ Pod Security Admission │ │
│ │ Optional policy engines such as Kyverno or Gatekeeper │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘

Корисний спосіб міркувати про Под — поставити по черзі три запитання. По-перше, від чийого імені працює процес усередині контейнера? По-друге, які додаткові привілеї ядра отримує цей процес? По-третє, які частини хоста Под спільно використовує чи монтує? Більшість небезпечних конфігурацій Подів ризиковані саме тому, що надто щедро відповідають на одне з цих запитань.

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

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

Зупиніться та подумайте: Розробник стверджує, що його контейнеру потрібен privileged: true, бо той має слухати порт 80. Перш ніж читати далі, вирішіть, чи це виправдання слушне, і назвіть найменший дозвіл, що розв’язав би зазначену проблему.

Відповідь у дусі мінімальних привілеїв — це зазвичай NET_BIND_SERVICE, а не privileged: true. Прив’язування до портів нижче 1024 контролюється конкретною можливістю Linux, тож надати всі можливості та пристрої хоста було б поганим обміном. Цей патерн часто з’являється під час оглядів безпеки: робоче навантаження має реальну потребу, але запропонований дозвіл значно ширший за неї.

Ця різниця важлива на іспиті KCSA та в реальних оглядах, бо Kubernetes дає кілька способів задовольнити одну й ту саму вимогу застосунку. Сервіс може надавати порт 80, поки контейнер слухає на 8080. Образ, що не працює від імені root, може володіти каталогами, які йому насправді потрібні. emptyDir може надати тимчасовий простір, не роблячи файлову систему образу змінною. Уміння полягає не в запам’ятовуванні кожного можливого поля; уміння полягає в зіставленні потреби з найменшим механізмом Kubernetes чи Linux, що її задовольняє.

SecurityContext: головна поверхня контролю

Розділ «SecurityContext: головна поверхня контролю»

Поле securityContext — це місце, де Kubernetes дозволяє задати ідентичність користувача, поведінку файлової системи, правила підвищення привілеїв, можливості Linux та вибір профілю seccomp. Воно може з’являтися на рівні Пода й на рівні контейнера. Налаштування рівня Пода — це зручні типові значення, тоді як налаштування рівня контейнера корисні, коли init-контейнеру чи sidecar потрібне щось відмінне від основного застосунку.

Посилена специфікація контейнера зазвичай починається з прибирання широких дозволів перед додаванням вузьких винятків. Наведений маніфест навмисно достатньо малий, щоб вивчати його поле за полем. Приклади команд використовують повну назву бінарника kubectl, тож вони залишаються придатними для копіювання в неінтерактивних оболонках, завданнях CI та скриптах лабораторних робіт.

Terminal window
kubectl create namespace pod-security-demo
apiVersion: v1
kind: Pod
metadata:
name: secure-web
namespace: pod-security-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 8080
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
privileged: false
capabilities:
drop:
- ALL
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
- name: tmp
mountPath: /tmp
volumes:
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
- name: tmp
emptyDir: {}

Цей маніфест відокремлює намір щодо безпеки від потреб застосунку. Коренева файлова система доступна лише для читання, але NGINX усе одно отримує каталоги з можливістю запису для файлів часу виконання через томи emptyDir. Процес працює під UID, що не є root, підвищення привілеїв вимкнено, а можливості Linux відкинуто. Профіль seccomp встановлено на RuntimeDefault, що дає середовищу виконання контейнерів змогу блокувати небезпечні системні виклики, не змушуючи учня писати власний профіль.

Зверніть увагу, що securityContext рівня Пода виражає типові значення, спільні для Пода, тоді як блок рівня контейнера виражає обмеження, специфічні для процесу web. Цей поділ — більше ніж стиль. Налаштування ідентичності рівня Пода зменшують повторення й роблять маніфест легшим для перегляду, але налаштування рівня контейнера все ще потрібні для таких засобів контролю, як readOnlyRootFilesystem, allowPrivilegeEscalation, privileged та можливості. Тому рецензенти мають читати обидва рівні як одну спільну політику, а не вважати жоден блок повним сам по собі.

Томи з можливістю запису також є частиною дизайну безпеки, а не зручністю, доданою постфактум. Багато образів припускають, що можуть створювати кеш-файли, PID-файли, тимчасові файли чи сокети за шляхами, що лежать у файловій системі образу. Коли ви робите цю файлову систему доступною лише для читання, ці припущення стають видимими. Уважний інженер використовує невдачу, щоб дізнатися, яким саме шляхам потрібен запис, а потім явно надає ці шляхи. Поспішний інженер вимикає налаштування «лише для читання» й втрачає корисний засіб контролю.

ПолеБезпечний напрямокЧому це важливоПоширений компроміс
runAsNonRootУстановіть trueЗапобігає випадковому виконанню від імені root, коли типове значення образу змінюєтьсяОбраз має працювати під UID, що не є root
runAsUserВикористовуйте ненульовий UIDРобить ідентичність часу виконання явною та придатною для переглядуМоже знадобитися коригування власника файлів
runAsGroupВикористовуйте ненульовий GIDУникає поведінки типової групи rootСпільним томам можуть знадобитися групові дозволи
fsGroupВикористовуйте лише там, де томам це потрібноДозволяє групі робочого навантаження писати в змонтовані томиМоже сповільнювати запуск тому на деяких типах сховища
readOnlyRootFilesystemУстановіть trueЗменшує закріплення та підміну в файловій системі образу контейнераЗастосункам потрібні явні томи для запису
allowPrivilegeEscalationУстановіть falseБлокує setuid та подібні шляхи отримання привілеївДеякі застарілі інструменти перестають працювати
privilegedЗалишайте false або опускайтеУникає широкого доступу до пристроїв хоста та можливостейСистемним агентам може знадобитися окремий виняток
capabilities.dropСпершу відкидайте ALLПрибирає навколишні привілеї Linux, що можуть бути не потрібні застосункуПовертайте вузькі можливості лише за обґрунтування
seccompProfileВикористовуйте RuntimeDefaultФільтрує ризиковані системні виклики через типові значення середовища виконанняДуже спеціалізованим застосункам може знадобитися власний профіль

Опрацьований приклад: припустімо, вебконтейнер відмовляє після того, як ви ввімкнули readOnlyRootFilesystem: true. Слабкою реакцією було б вимкнути цей засіб контролю, бо «застосунку потрібен запис». Сильніша реакція — знайти точні шляхи, до яких пише застосунок, і явно змонтувати ці шляхи. Це зберігає незмінну файлову систему застосунку захищеною, водночас даючи процесу контрольовану тимчасову зону.

Terminal window
kubectl apply -f secure-web.yaml
kubectl -n pod-security-demo describe pod secure-web
kubectl -n pod-security-demo logs secure-web

Якщо в логах згадується шлях на кшталт /var/cache/nginx чи /var/run, додайте монтування emptyDir для цього шляху й спробуйте знову. Це приклад звички старшого інженера з безпеки: зберігайте засіб контролю, коли це можливо, і робіть виняток достатньо точним, щоб його можна було переглянути.

Зробіть паузу й передбачте: Якщо на рівні Пода задано runAsUser: 1000, але один контейнер задає runAsUser: 0, яке значення застосовується до цього контейнера? Поясніть, чому така поведінка перевизначення важлива під час перегляду маніфесту.

securityContext рівня контейнера є більш специфічним, тож він перевизначає типове значення рівня Пода для цього контейнера. Під час перегляду це означає, що ви не можете зупинитися на блоці рівня Пода й припустити, що кожен контейнер безпечний. Init-контейнери, sidecar та контейнери застосунку — усі потребують перевірки, бо один контейнер, що перевизначає налаштування, може послабити Под.

Практична звичка перегляду — прочитати маніфест двічі. На першому проході шукайте широкі ознаки небезпеки: простори імен хоста, privileged, hostPath, додані можливості та виконання від імені root. На другому проході шукайте узгодженість: чи всі контейнери успадковують потрібного користувача, чи перевизначають якісь init-контейнери типові значення, і чи відповідають томи для запису реальним шляхам запису застосунку. Цей другий прохід ловить багато помилок, бо платформені команди часто посилюють основний контейнер, але забувають про допоміжний контейнер, що працює перед ним.

Можливості Linux: менше за root, але все ще потужні

Розділ «Можливості Linux: менше за root, але все ще потужні»

Можливості Linux розбивають стару модель «root може все» на вужчі привілеї. Це корисно, бо застосунку може знадобитися одна особлива дія, наприклад прив’язування до порту з малим номером, без потреби мати дозвіл адмініструвати мережевий стек чи монтувати файлові системи. Kubernetes дозволяє відкидати можливості й повертати лише ті, що обґрунтовані.

┌───────────────────────────────────────────────────────────────┐
│ LINUX CAPABILITIES │
├───────────────────────────────────────────────────────────────┤
│ │
│ TRADITIONAL MODEL │
│ │
│ ┌───────────────┐ ┌───────────────────────┐ │
│ │ UID 0 root │ ────────────▶ │ Broad system powers │ │
│ └───────────────┘ └───────────────────────┘ │
│ │
│ CAPABILITY MODEL │
│ │
│ ┌───────────────┐ ┌───────────────────────┐ │
│ │ Process │ ────────────▶ │ Specific permissions │ │
│ └───────────────┘ └───────────────────────┘ │
│ │
│ HIGH-RISK CAPABILITIES │
│ │
│ ┌───────────────────┬─────────────────────────────────────┐ │
│ │ SYS_ADMIN │ Mounts, namespaces, broad admin use │ │
│ │ NET_ADMIN │ Network configuration and routing │ │
│ │ SYS_PTRACE │ Inspect or manipulate processes │ │
│ │ DAC_OVERRIDE │ Bypass file permission checks │ │
│ │ SYS_RAWIO │ Raw I/O access │ │
│ └───────────────────┴─────────────────────────────────────┘ │
│ │
│ SAFER REVIEW PATTERN │
│ │
│ capabilities: │
│ drop: │
│ - ALL │
│ add: │
│ - NET_BIND_SERVICE │
│ │
└───────────────────────────────────────────────────────────────┘

Найважливіше правило перегляду — ставитися до SYS_ADMIN як до запиту, майже рівносильного привілейованому. Її назва звучить вузько, але на практиці вона відкриває багато операцій ядра, що можуть зламати ізоляцію. Розробник, який каже «ми не привілейовані, бо privileged: true відсутній», усе одно може запитувати небезпечний Под, якщо додано широкі можливості.

Хороший перегляд можливостей запитує про операцію, а не про назву можливості. Якщо робочому навантаженню потрібен порт 80, NET_BIND_SERVICE може бути достатньо. Якщо йому потрібно змінювати маршрути чи правила iptables, NET_ADMIN може бути технічно доречним, але це зазвичай має штовхати робоче навантаження до суворо контрольованого системного простору імен, а не до загального простору імен застосунків. Якщо йому потрібен SYS_ADMIN, команда має ставитися до цього як до винятку, що потребує перегляду архітектури.

Можливості легко недооцінити, бо їхні назви виглядають точними, але операційні наслідки залежать від навколишнього робочого навантаження. NET_ADMIN у демоні CNI, яким володіє платформена команда, що розгорнутий із перевіреного образу й ізольований у системному просторі імен, — це дуже інший ризик, ніж NET_ADMIN у вебзастосунку, зверненому до клієнтів. Поле однакове; межа довіри — ні. Саме тому перегляд безпеки Подів поєднує технічну перевірку полів із власністю та дизайном простору імен.

МожливістьТиповий запитРівень ризикуКраще запитання під час перегляду
NET_BIND_SERVICEПрив’язування до портів нижче 1024Низький, якщо ізольованоЧи може застосунок слухати на високому порту за Сервісом?
CHOWNЗміна власника файлівСереднійЧи можна виправити власника в образі чи під час налаштування тому?
SETUID / SETGIDЗміна ідентичності процесуСереднійЧи це застарілий патерн образу, який можна прибрати?
NET_ADMINЗміна маршрутів, iptables, інтерфейсівВисокийЧи це справді системний агент, а не навантаження застосунку?
SYS_PTRACEНалагодження чи дослідження процесівВисокийЧи може налагодження відбуватися в окремому тимчасовому процесі?
SYS_ADMINШироке адміністрування ядраКритичнийЧи навантаження фактично просить довіру рівня хоста?

Розгляньте цей небезпечний фрагмент. Він уникає privileged: true, але все ж надає широку можливість і дозволяє підвищення привілеїв. Це поєднання — саме той випадок, який рецензент має ставити під сумнів, бо воно послаблює одразу більш ніж один рівень ізоляції.

apiVersion: v1
kind: Pod
metadata:
name: risky-capability
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- SYS_ADMIN

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

Один тонкий момент для середовищ Kubernetes 1.35+ полягає в тому, що типова поведінка середовища виконання й політика допуску — це окремі речі. Середовище виконання може вже застосовувати типовий профіль seccomp, а образ контейнера може вже працювати під користувачем, що не є root, але ці факти не такі придатні для перегляду, як явний намір у маніфесті. Явні налаштування роблять дрейф видимим під час перегляду коду, оцінювання політики та реагування на інциденти. Коли майбутнє оновлення образу змінює користувача образу чи пише до нового шляху, засоби контролю рівня маніфесту допомагають перетворити цей дрейф на чітку відмову замість тихого послаблення.

Простори імен хоста: де ізоляція може зникнути

Розділ «Простори імен хоста: де ізоляція може зникнути»

Простори імен — це один із механізмів, завдяки яким контейнер відчуває себе ізольованим від хоста. Коли Под використовує hostNetwork, hostPID чи hostIPC, він навмисно спільно використовує частину простору імен вузла. Це іноді необхідно для інфраструктури кластера, але рідко доречно для звичайних навантажень застосунків.

┌───────────────────────────────────────────────────────────────┐
│ HOST NAMESPACE RISKS │
├───────────────────────────────────────────────────────────────┤
│ │
│ hostPID: true │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Container can see processes from the host PID namespace │ │
│ │ Risk: process discovery, signals, ptrace-style attacks │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ hostNetwork: true │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Container uses the node network namespace │ │
│ │ Risk: port conflicts, traffic visibility, spoofing │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ hostIPC: true │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Container shares host inter-process communication │ │
│ │ Risk: shared memory leakage and process interference │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ secure default: omit these fields or set them to false │
│ │
└───────────────────────────────────────────────────────────────┘

Налаштування просторів імен хоста небезпечні, бо вони змінюють те, що контейнер може спостерігати чи на що впливати. З hostPID процес усередині контейнера може мати змогу перелічувати процеси хоста, дізнаватися командні рядки й намагатися надсилати сигнали процесам, якщо це дозволяють інші дозволи. З hostNetwork контейнер оминає звичайний мережевий простір імен Пода й може конфліктувати з портами хоста чи поводитися як локальний для вузла сервіс. З hostIPC спільна пам’ять і механізми IPC стають проблемою розкриття даних.

Правильне запитання — не «чи підтримує Kubernetes це поле?». Правильне запитання — «який довірений компонент цього потребує і чому він мусить працювати на межі хоста?». Плагіни CNI, агенти моніторингу вузлів, плагіни пристроїв і деякі компоненти зберігання можуть мати слушні відповіді. Вебзастосунок, обробник черги чи API-сервіс зазвичай ні.

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

Налаштування хостаЩо воно спільно використовуєТипове легітимне використанняТипове значення для простору імен застосунків
hostNetwork: trueМережевий простір імен вузлаCNI, локальний для вузла DNS, окремі агенти моніторингуБлокувати або вимагати винятку
hostPID: trueПростір імен процесів вузлаГлибока діагностика вузла чи агенти безпекиБлокувати
hostIPC: trueПростір імен IPC вузлаРідкісні застарілі чи спеціалізовані навантаження вузлаБлокувати
Том hostPathФайли чи каталоги з вузлаПлагіни пристроїв, збирачі логів, агенти, звернені до kubeletБлокувати чутливі шляхи

Що сталося б, якби команда перемістила агента моніторингу вузлів і публічний вебзастосунок до одного простору імен, а потім позначила цей простір імен pod-security.kubernetes.io/enforce: privileged, щоб агент міг працювати? Опишіть ризик, створений для вебзастосунку.

Вебзастосунок успадковує послаблену політику допуску простору імен, хоча йому не потрібен доступ до хоста. Якщо цей застосунок скомпрометовано, зловмисник може подавати чи змінювати Поди, які використовують ті самі широкі дозволи, дозволені для агента моніторингу. Кращий дизайн — ізолювати довірені системні навантаження в окремому просторі імен і тримати простори імен застосунків на рівні baseline чи restricted.

Це головна причина, чому компонування просторів імен є рішенням щодо безпеки. Простір імен — це не лише організаційна тека; для PSA це межа, де мітки вирішують, які специфікації Подів допускаються. Якщо платформена команда змішує агентів вузлів, пакетні завдання, публічні API та навантаження орендарів в одному просторі імен, найсуворіше навантаження може бути обмежене найдозвільнішим винятком. Розділення класів навантажень дозволяє команді захищати звичайні застосунки, не вдаючи, ніби довірені компоненти вузла завжди можуть працювати під одним профілем.

Pod Security Standards: три профілі, різні призначення

Розділ «Pod Security Standards: три профілі, різні призначення»

Pod Security Standards, які зазвичай скорочують до PSS, визначають три профілі політики для специфікацій Подів. Вони не є повною програмою безпеки й не замінюють сканування образів, RBAC, NetworkPolicy чи виявлення під час виконання. Це вбудований словник для вирішення того, які функції Подів слід дозволяти під час допуску.

┌───────────────────────────────────────────────────────────────┐
│ POD SECURITY STANDARDS │
├───────────────────────────────────────────────────────────────┤
│ │
│ PRIVILEGED │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ No meaningful restrictions on pod security fields │ │
│ │ Use only for trusted system workloads that need host │ │
│ │ access, devices, or broad kernel interaction │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ BASELINE │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Blocks common privilege-escalation paths │ │
│ │ Suitable as a minimum bar for many application teams │ │
│ │ Still allows some settings that Restricted forbids │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ RESTRICTED │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Enforces stronger hardening expectations │ │
│ │ Requires non-root behavior and tighter runtime controls │ │
│ │ Best target for sensitive or mature application teams │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ PRACTICAL STARTING POINT │
│ Use Restricted when workloads are ready. Use Baseline as a │
│ minimum guardrail while teams remediate Restricted warnings. │
│ │
└───────────────────────────────────────────────────────────────┘

Назви профілів описують позицію політики, а не цінність робочого навантаження. Простір імен із міткою privileged не є важливішим за той, що має мітку restricted; він менш обмежений. Це важливо, бо команди іноді просять «privileged», ніби це знак старшинства. У зрілому кластері привілейовані простори імен мають бути рідкісними, чітко названими й обмеженими довіреними системними компонентами.

baseline корисний, коли кластеру потрібен негайний захист від очевидних шляхів підвищення привілеїв, не ламаючи багато наявних образів. Він блокує такі поля, як privileged, простори імен хоста та небезпечні можливості, але не вимагає, щоб кожне навантаження працювало не від імені root. restricted суворіший, бо він очікує виконання не від імені root, вимкненого підвищення привілеїв, відкинутих можливостей і seccomp. Перехід від baseline до restricted часто потребує очищення образу та файлової системи, а не лише зміни мітки.

Профілі найкраще розуміти як драбину міграції. privileged каже, що простір імен перебуває поза звичайною межею застосунків і має керуватися компенсувальними засобами контролю. baseline каже, що платформа блокуватиме найпоширеніші маршрути підвищення привілеїв, водночас даючи застарілим образам простір продовжувати працювати. restricted каже, що робоче навантаження спроєктовано для роботи з вузькою ідентичністю, вузькою файловою системою, вузькими можливостями та запобіжниками часу виконання. Команди, що ставляться до профілів як до міток для суперечок, зазвичай мають труднощі; команди, що ставляться до них як до інженерних цілей, можуть планувати роботу.

Засіб контролюPrivilegedBaselineRestricted
hostNetworkДозволеноЗаблокованоЗаблоковано
hostPIDДозволеноЗаблокованоЗаблоковано
hostIPCДозволеноЗаблокованоЗаблоковано
privileged: trueДозволеноЗаблокованоЗаблоковано
Небезпечні можливостіДозволеноЗаблокованоЗаблоковано
Чутливе використання hostPathДозволеноЗаблокованоЗаблоковано
Виконання під UID 0ДозволеноДозволеноЗаблоковано
allowPrivilegeEscalation: trueДозволеноІноді дозволеноЗаблоковано
Відсутній профіль seccompДозволеноДозволеноЗаблоковано
Необмежені типи томівДозволеноОбмеженоОбмежено суворіше

Обираючи профіль, починайте з класу робочого навантаження. Простори імен застосунків мають прагнути до restricted, особливо для сервісів, звернених до інтернету чи орендарів. Застарілі застосунки, яким усе ще потрібен root, можуть тимчасово підійти під baseline, поки команда виправляє власника образу та шляхи запису. Інфраструктура кластера не повинна спільно використовувати простір імен із застосунками лише тому, що їй потрібен привілейований доступ.

Немає нічого ганебного у використанні baseline як тимчасового кроку, але він не повинен ставати постійним виправданням. Розумний план міграції називає блокери: які образи все ще працюють від імені root, яким шляхам усе ще потрібні томи для запису, які контейнери все ще покладаються на типові можливості, і які команди володіють виправленнями. Без цього переліку простір імен може роками сидіти на baseline, поки всі припускають, що хтось інший зробить його готовим до restricted. Попередження допуску, події аудиту та контрольні списки перегляду розгортань перетворюють цей нечіткий намір на роботу, з якою можна щось зробити.

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

┌───────────────────────────────────────────────────────────────┐
│ PROFILE SELECTION PATH │
├───────────────────────────────────────────────────────────────┤
│ │
│ Does the workload administer node networking, devices, │
│ storage, process visibility, or other host-level features? │
│ │
│ yes ──▶ dedicated system namespace ──▶ privileged │
│ │ │
│ no │
│ ▼ │
│ Can the image run as non-root with explicit writable mounts, │
│ dropped capabilities, no privilege escalation, and seccomp? │
│ │
│ yes ────────────────────────────────▶ restricted │
│ │ │
│ no │
│ ▼ │
│ Is there a time-boxed remediation plan to remove root, │
│ mutable filesystem assumptions, or legacy privileges? │
│ │
│ yes ────────────────────────────────▶ baseline + warn │
│ │ │
│ no │
│ ▼ │
│ Escalate for architecture review before admitting workload │
│ │
└───────────────────────────────────────────────────────────────┘

Pod Security Admission: примусове застосування стандартів через мітки простору імен

Розділ «Pod Security Admission: примусове застосування стандартів через мітки простору імен»

Pod Security Admission, який зазвичай скорочують до PSA, — це вбудований контролер допуску Kubernetes, що застосовує Pod Security Standards. У Kubernetes 1.35 та поточних підтримуваних версіях він є стандартною вбудованою заміною вилученої функції PodSecurityPolicy. PSA навмисно простіший за повноцінний рушій політик: він оцінює Поди за мітками профілю на просторі імен.

┌───────────────────────────────────────────────────────────────┐
│ PSA ENFORCEMENT MODES │
├───────────────────────────────────────────────────────────────┤
│ │
│ ENFORCE │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Blocks pods that violate the selected profile │ │
│ │ Use when the namespace is ready for hard enforcement │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ WARN │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Allows the pod but returns warnings to the API client │ │
│ │ Use to teach developers before raising enforcement │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ AUDIT │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Allows the pod but records violations in audit events │ │
│ │ Use to measure readiness and find hidden violations │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ COMMON COMBINATION │
│ enforce baseline, warn restricted, audit restricted │
│ │
└───────────────────────────────────────────────────────────────┘

Три режими дозволяють командам піднімати планку, не спричиняючи збою. Простір імен може примусово застосовувати baseline, тож очевидно небезпечні Поди блокуються, водночас попереджаючи та проводячи аудит проти restricted. Розробники можуть продовжувати постачати сумісні навантаження, але вони бачать попередження, що показують, які поля треба змінити, перш ніж простір імен зможе перейти до суворішого примусового застосування.

Цей поділ між enforce, warn та audit — одна з найкорисніших операційних функцій PSA. Примусове застосування захищає кластер негайно, попередження навчають особу, що подає маніфест, а записи аудиту дозволяють платформеним командам вимірювати роботу, що відбувається поза інтерактивним терміналом. У здоровому розгортанні режими попередження та аудиту йдуть попереду примусового застосування. Вони виявляють, які навантаження зламалися б під наступним суворішим профілем, перш ніж платформена команда перемкне блокувальну мітку.

apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest

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

Зафіксовані версії — це інструмент керування змінами, а не спосіб назавжди уникати оновлень. Якщо кластер фіксує версію політики під час оновлення Kubernetes, платформена команда має запланувати наступний перегляд, щоб порівняти зафіксований профіль із новим типовим профілем. Інакше організація може випадково заморозити старі припущення й пропустити поліпшення у стандарті. Для цілей іспиту важливий патерн полягає в тому, що кожен режим може мати відповідну мітку *-version, і сама лише назва профілю не є цілою політикою.

Terminal window
kubectl label namespace pod-security-demo \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/warn-version=latest \
--overwrite

Тепер уявіть, що розробник подає Под, який працює від імені root, але не використовує privileged: true, простори імен хоста чи небезпечні можливості. З enforce: baseline Под може бути допущено, бо baseline зосереджується на відомих шляхах підвищення привілеїв і не повністю вимагає виконання не від імені root. З warn: restricted розробник усе одно отримує зворотний зв’язок, бо restricted очікує налаштувань, що не є root, та інших засобів посилення.

Зробіть паузу й передбачте: Ваш кластер примусово застосовує baseline і попереджає про restricted. Команда подає Под, що працює під UID 0, задає allowPrivilegeEscalation: false, відкидає всі можливості й використовує seccomp RuntimeDefault. Под буде заблоковано, попереджено, і те, і те, чи нічого? Поясніть, який профіль зумовлює кожен результат.

Хороша відповідь відокремлює примусове застосування від попередження. Под не блокується лише за роботу від імені root під baseline, якщо він уникає полів, що baseline забороняє. Він усе одно має отримати попередження restricted, бо restricted очікує, що навантаження працюватиме не від імені root. Саме тому поєднання режимів PSA корисні: вони дозволяють платформеним командам примусово застосовувати мінімум, водночас сигналізуючи про наступну ціль.

Під час налагодження реальних попереджень скопіюйте текст попередження до pull request чи тікета й перекладіть його на зміни в маніфесті. «Порушує restricted» менш корисне, ніж «контейнер api має задати runAsNonRoot: true, використати ненульовий UID, відкинути всі можливості й задати allowPrivilegeEscalation: false». Цей крок перекладу допомагає власникам застосунку засвоїти правило й дає рецензентам конкретний спосіб перевірити наступну ревізію.

Опрацьований приклад: налагодження відмови PSA

Розділ «Опрацьований приклад: налагодження відмови PSA»

Помилка Pod Security Admission корисна, якщо читати її як мапу назад до полів у маніфесті. Сервер API зазвичай повідомляє порушений профіль і називає поля-порушники. Замість того щоб гадати, скопіюйте кожне порушення до невеликого списку усунення, а потім вирішіть, чи виправляти навантаження, чи перенести його до простору імен, де виняток виправданий.

Цей процес особливо важливий під час реагування на інциденти чи міграційної роботи, бо повідомлення PSA можуть перелічувати кілька порушень одразу. Команди іноді виправляють перше назване поле, повторюють спробу, а потім виявляють наступний блокер, що марнує час і викликає роздратування політикою. Краща звичка — зібрати всю відмову, визначити кожну категорію полів і вирішити, чи описує маніфест звичайний застосунок, чи компонент рівня хоста. Це рішення визначає, чи ви посилюєте Под, чи ізолюєте його як виняток.

Почніть із простору імен, що примусово застосовує baseline, бо це дає вам чітку відмову щоразу, коли маніфест перетинає мінімальну межу безпеки застосунку.

Terminal window
kubectl create namespace psa-debug
kubectl label namespace psa-debug \
pod-security.kubernetes.io/enforce=baseline \
pod-security.kubernetes.io/enforce-version=latest \
--overwrite

Застосуйте Под, що порушує baseline кількома способами, а потім прочитайте відповідь як структуровані докази, а не як загальне повідомлення про невдачу.

apiVersion: v1
kind: Pod
metadata:
name: blocked-debug
namespace: psa-debug
spec:
hostNetwork: true
hostPID: true
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
- SYS_ADMIN
Terminal window
kubectl apply -f blocked-debug.yaml

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

Підказка про відмовуПоле для перевіркиІмовірне виправленняКоли виняток може бути слушним
Використовує мережу хостаspec.hostNetworkПрибрати поле й надавати через СервісЛокальні для вузла мережеві компоненти
Використовує простір імен PID хостаspec.hostPIDПрибрати полеАгенти безпеки чи глибока діагностика
Привілейований контейнерsecurityContext.privilegedУстановити false або опуститиПлагіни пристроїв чи окремі агенти вузлів
Додає заборонену можливістьsecurityContext.capabilities.addВідкинути ALL, додати вузьку можливість лише за потребиКомпоненти CNI чи мережі вузлів
Працює від імені root під restrictedrunAsUser, USER образуЗадати ненульовий UID і runAsNonRoot: trueТимчасова міграція застарілого під baseline

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

apiVersion: v1
kind: Pod
metadata:
name: corrected-app
namespace: psa-debug
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}

Зверніть увагу на послідовність перегляду. По-перше, визначте, що навантаження має робити. По-друге, зіставте кожне відхилене поле з ризиком. По-третє, приберіть поле чи замініть його вужчим механізмом. По-четверте, якщо поле справді потрібне, ізолюйте навантаження замість того, щоб змінювати політику для непов’язаних застосунків.

Виправлений Под навмисно нудний. Він спить, працює під користувачем, що не є root, відкидає можливості, використовує профіль seccomp середовища виконання й пише лише до названого тимчасового тому. Ця нудна форма — саме те, чого ви хочете для більшості навантажень застосунків, бо нудні маніфести легше переглядати, легше шаблонізувати та легше примусово застосовувати послідовно. Якщо застосунок не може вписатися в цю форму, перегляд має виявити конкретну причину, а не нечітке твердження, що «безпека ламає застосунок».

Привілейовані контейнери: ставтеся до них як до рішень про довіру вузла

Розділ «Привілейовані контейнери: ставтеся до них як до рішень про довіру вузла»

privileged: true — одна з найчіткіших ознак небезпеки в маніфесті Пода. Він надає контейнеру широкий доступ до пристроїв хоста й можливостей, що може змусити контейнер поводитися радше як процес на вузлі, ніж як ізольований процес застосунку. Деякій інфраструктурі кластера ця сила потрібна, але більшості навантажень застосунків — ні.

┌───────────────────────────────────────────────────────────────┐
│ PRIVILEGED CONTAINERS │
├───────────────────────────────────────────────────────────────┤
│ │
│ privileged: true grants │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Access to host devices │ │
│ │ Broad Linux capability set │ │
│ │ Weakened runtime isolation │ │
│ │ Much larger node-compromise blast radius │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ legitimate examples │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ CNI plugins that configure node networking │ │
│ │ Device plugins that expose hardware │ │
│ │ Selected node monitoring or security agents │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ review expectation │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Dedicated namespace │ │
│ │ Narrow service account and RBAC │ │
│ │ Clear owner and documented justification │ │
│ │ No co-location with ordinary application workloads │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘

Поширена помилка початківця — розглядати privileged як інструмент усунення проблем. Щось відмовляє, команда задає privileged: true, і застосунок запускається. Цей результат доводить лише те, що початкова проблема стосувалася дозволів; він не доводить, що широкий дозвіл був необхідним. Старший перегляд наполягає на найменшому успішному дозволі й запитує, чи може дизайн застосунку взагалі уникнути залежності від хоста.

Наприклад, сервіс, якому потрібен малий порт, може використати зіставлення Сервісу Kubernetes порту 80 до високого containerPort. Процес, якому потрібен тимчасовий запис, може використати emptyDir. Процес, якому потрібно читати конфігурацію, може використати ConfigMap чи Secret. Под, що просить привілейований режим, має вміти пояснити, чому абстракцій, нативних для Kubernetes, недостатньо.

Існує також проблема підзвітності з постійними привілейованими налаштуваннями. Через шість місяців після термінового виправлення особа, що додала privileged: true, могла перейти до іншої команди, застосунок міг змінитися, а початкова причина могла більше не існувати. Якщо маніфест не містить задокументованого шляху для винятку поза YAML, майбутні рецензенти бачать лише потужне налаштування без контексту. Ставлення до привілейованого доступу як до рішення про довіру вузла змушує команду фіксувати власність, технічну необхідність та очікування щодо переоцінювання.

Заявлена потребаУникайте privileged, спробувавшиЧому це безпечніше
Прив’язування до порту 80Сервіс port: 80 до targetPort: 8080 або NET_BIND_SERVICEТримає пристрої хоста та широкі можливості подалі
Запис тимчасових файлівemptyDir, змонтований за конкретним шляхомЗберігає кореневу файлову систему лише для читання
Читання конфігурації застосункуТом ConfigMap чи SecretУникає монтувань файлової системи хоста
Збір метрик застосункуПатерн sidecar чи ServiceMonitorУникає мережі хоста та видимості процесів
Налагодження процесуЕфемерний процес налагодження з контрольованим RBACУникає постійних підвищених налаштувань часу виконання

Зупиніться та подумайте: Якщо Под відхилено через baseline, бо він задає privileged: true, які докази переконали б вас, що він належить до привілейованого простору імен, а не має бути переспроєктований? Напишіть докази так, ніби ви залишаєте коментар до огляду.

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

Той самий стандарт стосується агентів від постачальників. Чарт від поважного постачальника все одно може запитувати дозволи, надто широкі для моделі ризику вашого кластера. Перш ніж встановлювати його до привілейованого простору імен, прочитайте згенеровані маніфести, зрозумійте, якому DaemonSet потрібен доступ до хоста, та обмежте права на розгортання навколо цього простору імен. Довіра до постачальника зменшує деякі питання щодо ланцюга постачання; вона не прибирає потреби обмежувати потужні Поди.

Seccomp та підвищення привілеїв: запобіжники часу виконання

Розділ «Seccomp та підвищення привілеїв: запобіжники часу виконання»

Seccomp фільтрує системні виклики — інтерфейс, який процеси використовують, щоб попросити ядро виконати роботу. Контейнеру може бути не потрібен кожен можливий syscall, щоб обслуговувати HTTP, обробляти повідомлення чи виконувати пакетне завдання. Типовий профіль seccomp середовища виконання блокує окремі небезпечні чи незвичні системні виклики, водночас зберігаючи сумісність для нормальних навантажень.

┌───────────────────────────────────────────────────────────────┐
│ SECCOMP PROFILES │
├───────────────────────────────────────────────────────────────┤
│ │
│ Unconfined │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ No seccomp syscall filtering from the container runtime │ │
│ │ Highest compatibility, weakest syscall restriction │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ RuntimeDefault │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Uses the container runtime's default seccomp profile │ │
│ │ Good default for most application workloads │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Localhost │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Uses a custom profile installed on the node │ │
│ │ Useful for specialized hardening with operational care │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ recommended application setting │
│ │
│ securityContext: │
│ seccompProfile: │
│ type: RuntimeDefault │
│ │
└───────────────────────────────────────────────────────────────┘

allowPrivilegeEscalation: false — це ще один запобіжник часу виконання. Він не дає процесу здобути більше привілеїв, ніж має його батьківський процес, через механізми на кшталт бінарників setuid. Це особливо корисно, коли образ містить застарілі інструменти, не потрібні застосунку. Якщо допоміжний бінарник setuid несподівано перестає працювати після застосування цього налаштування, це сигнал дизайну: або допоміжний інструмент непотрібний і має бути прибраний, або навантаження потребує явного винятку, який треба переглянути.

Seccomp, відкинуті можливості та вимкнене підвищення привілеїв найсильніші, коли використовуються разом. Відкидання можливостей прибирає широкі сили ядра. Вимкнення підвищення привілеїв не дає процесу здобути нові сили пізніше. Seccomp зменшує набір операцій ядра, доступних навіть якщо процес скомпрометовано. Жоден із цих засобів контролю не є досконалим окремо, але разом вони ускладнюють переміщення після компрометації.

Корисно відокремлювати проблеми сумісності від проблем безпеки, коли ці засоби контролю виявляють старі припущення. Якщо допоміжний бінарник відмовляє через вимкнене підвищення привілеїв, команда має запитати, чи взагалі належить цей помічник до образу. Якщо syscall заблоковано типовим профілем seccomp середовища виконання, команда має визначити syscall і функцію, що його потребує, а не одразу перемикатися на Unconfined. Мета — не змусити кожну невдачу зникнути; мета — зробити вимогу до дозволу точною.

Засіб контролюБлокує чи зменшуєСимптом невдачі, коли застосунок від цього залежитьРеакція під час перегляду
seccompProfile: RuntimeDefaultДеякі ризиковані syscallЛоги застосунку згадують «operation not permitted» для дії на кшталт syscallПідтвердити потребу, потім розглянути власний профіль лише за обґрунтування
allowPrivilegeEscalation: falsesetuid та подібне підвищенняЗастарілий допоміжний бінарник не може здобути підвищені дозволиПрибрати помічника чи задокументувати виняток
capabilities.drop: ["ALL"]Навколишні можливості LinuxПрив’язування до малого порту чи операція зі зміни власника відмовляєДодати вузьку можливість чи переспроєктувати
readOnlyRootFilesystem: trueЗапис до файлової системи образуЗастосунок не може писати кеш, pid, тимчасові файли чи логиЗмонтувати явні томи для запису

Що сталося б, якби ви задали allowPrivilegeEscalation: false, але залишили privileged: true на тому самому контейнері? Поясніть, чому суперечливі налаштування ускладнюють перегляди безпеки.

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

Це правило сукупного ефекту — наскрізна тема в безпеці Подів. runAsNonRoot: true цінне, але менш переконливе, якщо той самий контейнер додає широкі можливості. Коренева файлова система лише для читання цінна, але менш переконлива, якщо Под монтує чутливий шлях хоста для читання-запису. Seccomp цінний, але менш переконливий, якщо контейнер працює привілейовано. Звичка рівня KCSA — читати маніфест як систему дозволів, а не як контрольний список окремих хороших і поганих полів.

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

Розділ «Проєктування винятків без послаблення для всіх»

Реальні кластери містять винятки. Мета — не вдавати, ніби кожен Под можна негайно обмежити; мета — не дати одному винятку стати типовим для непов’язаних навантажень. Простори імен є головною межею PSA, тож дизайн винятків починається з розділення просторів імен.

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

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

apiVersion: v1
kind: Namespace
metadata:
name: node-agents
labels:
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: privileged
pod-security.kubernetes.io/audit-version: latest

Самої лише цієї мітки простору імен недостатньо для безпеки. Привілейований простір імен має також мати вузький RBAC, контрольовані дозволи на розгортання, чітку власність і моніторинг. PSA вирішує, чи допускаються специфікації Подів; він не вирішує, хто може створювати Поди, які образи довірені й чи навантаження поводиться правильно під час виконання.

Засіб контролю виняткуПризначенняПриклад запитання для перегляду
Окремий простір іменЗапобігає перетіканню дозволів до застосунківЧи заборонено непов’язаним навантаженням бути в цьому просторі імен?
Вузький RBACОбмежує тих, хто може створювати потужні ПодиЯкі ідентичності можуть створювати чи оновлювати Поди тут?
Власник навантаженняСтворює підзвітністьЯка команда реагує, якщо агента скомпрометовано?
Контроль образівЗменшує ризик ланцюга постачанняЧи зафіксовано образ і взято з затвердженого реєстру?
Моніторинг під час виконанняВиявляє зловживання після допускуЧи видимі події привілейованого навантаження командам безпеки?
Перегляд з обмеженням у часіЗапобігає постійним випадковим виняткамКоли виняток буде переоцінено?

Для цілей іспиту KCSA знайте, що PSA є обмеженим простором імен і базованим на профілях. Для реальних операцій ідіть на рівень глибше: мітки простору імен — лише одна частина площини управління. RBAC, політика образів, NetworkPolicy, ізоляція вузлів, логування та реагування на інциденти — усі визначають, чи залишається привілейований виняток обмеженим.

Один практичний патерн — вести реєстр винятків поза маніфестами. Реєстр не має бути вишуканим, але він має фіксувати простір імен, навантаження, власника, причину, запитані поля, дату затвердження та дату наступного перегляду. Під час оновлень кластера чи інцидентів безпеки цей реєстр допомагає відповідальним особам визначити, які навантаження мають довіру рівня хоста та які команди можуть їх пояснити. Без нього привілейовані простори імен стають інституційною пам’яттю, прихованою в мітках.

Патерни та антипатерни

Розділ «Патерни та антипатерни»

Патерни безпеки Подів найкорисніші, коли вони пов’язують клас навантаження з повторюваною формою перегляду. Платформена команда не повинна змушувати кожного розробника наново винаходити той самий маніфест із виконанням не від імені root, лише для читання та відкиданням можливостей, і не повинна затверджувати кожен виняток як разову розмову. Хороші патерни роблять безпечний шлях легким шляхом, водночас залишаючи контрольований маршрут для навантажень, що справді перебувають на межі вузла.

ПатернКоли його використовуватиЧому він працюєМіркування щодо масштабування
Простори імен застосунків із restricted за замовчуваннямНові сервіси, навантаження, звернені до інтернету, та команди із сучасними образамиВін робить виконання не від імені root, відкидання можливостей, seccomp і явні шляхи запису нормальним очікуваннямНадавайте шаблони та перевірки CI, щоб розробники отримували зворотний зв’язок до того, як допуск відхилить Под
Примусовий baseline із попередженням restricted під час міграціїЗастарілі простори імен, що все ще містять образи з root чи припущення про змінну файлову системуВін блокує найризикованіші поля негайно, водночас показуючи залишок роботи до готовності restrictedВідстежуйте кількість попереджень за власником, інакше міграція застрягне на baseline
Окремі привілейовані системні простори іменАгенти CNI, зберігання, пристроїв та безпеки вузлів, яким потрібен доступ рівня хостаВін не дає винятками довіри вузла перетікати до звичайних навантажень застосунківОбмежуйте права на розгортання та переглядайте маніфести постачальників перед наданням доступу до простору імен
Явний дизайн шляхів для записуЗастосунки, яким потрібні розташування для кешу, PID, сокетів чи тимчасових файлівВін зберігає файлову систему образу лише для читання, водночас даючи процесу мінімальний тимчасовий простірТримайте шляхи запису задокументованими в чарті чи маніфесті, щоб майбутні зміни образу залишалися придатними для перегляду

Антипатерни зазвичай починаються як швидкі рішення. Команда хоче виправити невдале розгортання, чарту моніторингу потрібен доступ до хоста, або старий образ припускає скрізь власника root. Швидке рішення стає небезпечним, коли його копіюють до шаблонів, спільних просторів імен чи постійних винятків. Лікування — це не лише суворіше налаштування; це процес перегляду, що запитує про фактичну операцію навантаження, найменший дозвіл, що її уможливлює, і межу, що її обмежує.

АнтипатернЩо йде не такЧому команди в це впадаютьКраща альтернатива
Privileged як перемикач налагодженняПод отримує широку довіру рівня хоста для невідомої проблемиЦе швидко, часто змушує симптом зникнути й уникає вивчення точного відсутнього дозволуВідтворіть невдачу, визначте операцію та надайте вузьку можливість чи том для запису лише за потреби
Один простір імен для застосунків і агентів вузлівПоди застосунків успадковують послаблений допуск, бо системному агенту потрібен доступ до хостаКомпонування простору імен слідує власності команди, а не межам безпекиРозділіть класи навантажень на простори імен із різними мітками PSA та засобами контролю RBAC
Посилений основний контейнер зі слабким init-контейнеромПод усе одно порушує політику чи стартує з ризикованим шляхом помічникаПерегляди зосереджуються на довготривалому контейнері застосунку й пропускають логіку налаштуванняПеревіряйте securityContext кожного контейнера, включно з init-контейнерами та sidecar
Попередження без власностіПопередження restricted накопичуються, поки ніхто їм не довіряє й не читаєРежим попередження ввімкнено як галочку, а не як програму міграціїСпрямовуйте попередження до власників сервісів, створюйте тікети усунення та піднімайте примусове застосування лише після тестування

Структура прийняття рішень

Розділ «Структура прийняття рішень»

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

Запитання для переглядуЯкщо відповідь «так»Якщо відповідь «ні»
Чи навантаження конфігурує мережу вузла, зберігання, пристрої, видимість процесів чи іншу функцію рівня хоста?Ставтеся до нього як до системного навантаження, розмістіть його в окремому просторі імен і переглядайте привілейовані чи baseline-винятки з RBAC та засобами контролю власностіПродовжуйте переглядати його як навантаження застосунку, що має прагнути до restricted
Чи може кожен контейнер працювати під ненульовим UID із runAsNonRoot: true?Збережіть чи вимагайте сумісні з restricted налаштування ідентичностіВикористовуйте baseline тимчасово лише з планом усунення проблем образу та власником
Чи може коренева файлова система бути лише для читання з явними томами для запису?Задайте readOnlyRootFilesystem: true та назвіть шляхи записуВизначте точні записи перед послабленням засобу контролю; уникайте широких змінних файлових систем
Чи всі можливості Linux непотрібні чи достатньо вузькі для обґрунтування?Відкиньте ALL і додайте лише переглянуту можливість, якщо немає кращого дизайнуВідхиляйте широкі додавання на кшталт SYS_ADMIN для звичайних застосунків і ескалюйте випадки рівня хоста
Чи можна розв’язати попередження PSA перед зміною примусового застосування?Перемістіть простір імен до примусового застосування restricted після тестуванняТримайте enforce на baseline, попереджайте про restricted і відстежуйте залишкові блокери

Остаточне рішення має читатися як інженерна нотатка, а не як гасло. «Затверджено для restricted, бо всі контейнери працюють під UID 1000, відкидають можливості, використовують RuntimeDefault і пишуть лише до /tmp та /var/cache/app» — корисне. «Затверджено, бо пройшло безпеку» — ні. Чіткі рішення навчають майбутніх рецензентів, які докази мали значення, і полегшують виявлення дрейфу, коли навантаження змінюється.

  • Pod Security Admission замінив PodSecurityPolicy після того, як PodSecurityPolicy було визнано застарілим і вилучено з Kubernetes. PSA простіший, бо використовує стандартні профілі та мітки простору імен замість власних об’єктів політики.

  • Restricted не означає непридатний для нормальних застосунків. Більшість HTTP-сервісів, обробників і пакетних завдань можуть працювати під налаштуваннями restricted, щойно образи уникнуть припущень про власника root і пишуть лише до явно змонтованих шляхів.

  • Под може виглядати частково посиленим і все одно бути небезпечним, якщо одне поле надає широкий доступ. Наприклад, allowPrivilegeEscalation: false не робить привілейований контейнер звичайним контейнером застосунку.

  • Попередження — це інструмент міграції, бо warn: restricted може навчити розробників, які поля виправити, перш ніж платформена команда змінить enforce з baseline на restricted.

ПомилкаЧому вона трапляєтьсяЯк її виправити
Виконання контейнерів застосунку від імені root за замовчуваннямСкомпрометований процес стартує з більшими повноваженнями над файловою системою та процесами всередині контейнераЗадайте runAsNonRoot: true і ненульовий runAsUser, який образ підтримує
Задання privileged: true для виправлення непоясненої невдачіВоно надає широкий доступ рівня хоста й приховує реальну вимогу до дозволуВизначте операцію, що відмовляє, потім використайте вужчу можливість, том чи абстракцію Kubernetes
Забування відкинути можливості LinuxТипові чи додані можливості можуть дозволяти дії, не потрібні застосункуВикористовуйте capabilities.drop: ["ALL"] і додавайте лише переглянуту вузьку можливість
Примусове застосування privileged у змішаному просторі імен застосунківКожне навантаження в просторі імен успадковує послаблену межу допускуПеремістіть системних агентів до окремого простору імен і тримайте простори імен застосунків на baseline чи restricted
Увімкнення readOnlyRootFilesystem без томів для записуЗастосунок може відмовити, коли пише кеш, pid, тимчасові файли чи файли часу виконанняТримайте кореневу файлову систему лише для читання й монтуйте emptyDir за явними шляхами запису
Ставлення до попереджень PSA як до нешкідливого шумуПопередження часто показують саме те, що блокує майбутню міграцію до суворішого примусового застосуванняВідстежуйте попередження, призначайте власників і усувайте їх перед підняттям примусового застосування
Перегляд лише securityContext рівня ПодаПеревизначення рівня контейнера може послабити один контейнер, навіть коли типові значення Пода виглядають безпечнимиПеревіряйте кожен контейнер застосунку, sidecar та init-контейнер на перевизначення
Використання просторів імен хоста для звичайного усунення проблемДоступ до мережі чи PID хоста розкриває інформацію рівня вузла й може створювати шляхи підвищення привілеївВикористовуйте контрольовані процеси налагодження й прибирайте налаштування просторів імен хоста зі специфікацій застосунків
  1. Ваша команда розгортає API-Под у простір імен із enforce: baseline та warn: restricted. Под працює під UID 0, відкидає всі можливості, використовує seccomp RuntimeDefault і не використовує простори імен хоста. Розгортання вдається, але виводить попередження. Як вам інтерпретувати результат, і що команда має змінити, перш ніж простір імен перейде до примусового застосування restricted?

    Відповідь

    Под проходить baseline, бо він уникає головних полів підвищення привілеїв, що baseline блокує, як-от привілейований режим, простори імен хоста та небезпечні можливості. Він попереджає під restricted, бо restricted очікує виконання не від імені root і сильнішого посилення. Команда має оновити образ чи специфікацію Пода, щоб процес працював під ненульовим UID, задати runAsNonRoot: true, підтвердити дозволи файлів і томи для запису та зберегти наявні відкинуті можливості й налаштування seccomp. Головне — ставитися до попередження як до зворотного зв’язку міграції, а не як до помилки, яку треба ігнорувати.

  2. Розробник каже, що його сервісу потрібен privileged: true, бо той має слухати на порту 80. Ви переглядаєте маніфест для простору імен застосунків, що прагне до безпеки restricted. Який альтернативний дизайн ви порекомендували б і чому він безпечніший?

    Відповідь

    Порекомендуйте слухати на високому порту контейнера, як-от 8080, і надавати його через Сервіс Kubernetes із port: 80 та targetPort: 8080. Якщо процес справді має прив’язуватися до малого порту всередині контейнера, розгляньте додавання лише NET_BIND_SERVICE після відкидання всіх можливостей. Обидва варіанти безпечніші за привілейований режим, бо вони уникають надання пристроїв хоста, широких можливостей і послабленої ізоляції часу виконання заради вузької мережевої потреби.

  3. Агент моніторингу відмовляє після того, як платформена команда змінює його простір імен із privileged на baseline. Відмова згадує hostNetwork та hostPID. Агент збирає метрики рівня вузла, тоді як звичайні вебзастосунки також працюють у тому самому просторі імен. Який найкращий план усунення проблеми?

    Відповідь

    Не послаблюйте спільний простір імен застосунків назад до privileged. Створіть окремий простір імен для довірених агентів вузлів, застосуйте найменш дозвільні мітки, що дозволяють агента, обмежте тих, хто може там розгортати, за допомогою RBAC і тримайте звичайні вебзастосунки в просторі імен baseline чи restricted. Агент моніторингу може мати легітимну потребу рівня хоста, але його спільне розміщення зі звичайними застосунками поширює виняток на навантаження, яким він не потрібен.

  4. Под відхилено примусовим застосуванням restricted після того, як ви додали readOnlyRootFilesystem: true. Застосунок пише тимчасові файли під /tmp і файли часу виконання під /var/run/app. Колега пропонує задати readOnlyRootFilesystem: false. Як ви виправили б Под, зберігши засіб контролю безпеки?

    Відповідь

    Збережіть readOnlyRootFilesystem: true і змонтуйте явні томи для запису за шляхами, потрібними застосунку, як-от томи emptyDir для /tmp та /var/run/app. Це задовольняє вимогу застосунку, не дозволяючи запис у всю файлову систему образу. Результат придатніший для перегляду, бо розташування для запису названі в маніфесті, а зловмисник має менше місць для зміни бінарників чи створення закріплення.

  5. Під час перегляду ви знаходите Под із capabilities.add: ["SYS_ADMIN"], allowPrivilegeEscalation: false та privileged: false. Власник стверджує, що Под безпечний, бо він не привілейований і підвищення вимкнено. Який ризик залишається, і що вам запитати далі?

    Відповідь

    SYS_ADMIN залишається можливістю високого ризику навіть без privileged: true; вона охоплює широкі операції ядра й може підірвати ізоляцію контейнера. allowPrivilegeEscalation: false запобігає здобуттю нових привілеїв пізніше, але не прибирає вже наданого широкого привілею. Запитайте, яка саме операція потребує SYS_ADMIN, чи може вужча можливість чи абстракція Kubernetes її замінити, і чи належить навантаження до окремого системного простору імен, якщо потреба справді рівня хоста.

  6. securityContext рівня Пода задає runAsUser: 1000 та seccompProfile: RuntimeDefault. Один init-контейнер перевизначає runAsUser: 0 й додає NET_ADMIN. Основний контейнер застосунку виглядає сумісним із restricted. Як вам оцінити цей Под?

    Відповідь

    Оцінюйте кожен контейнер, включно з init-контейнерами та sidecar, бо контекст безпеки рівня контейнера може перевизначати типові значення рівня Пода. Init-контейнер послаблює Под, працюючи від імені root і додаючи NET_ADMIN, що може порушувати restricted і, можливо, baseline залежно від точної політики. Перегляд має запитати, чому init-контейнеру потрібне адміністрування мережі, чи можна перенести цю роботу за межі Пода, і чи може Под послідовно зберігати виконання не від імені root в усіх контейнерах.

  7. Команда хоче перемістити застарілий простір імен від відсутніх міток PSA одразу до enforce: restricted. Пробний запуск показує, що багато Подів відмовляє, бо образи працюють від імені root і пишуть під /var/cache. Яка поетапна міграція зменшила б ризик, не залишаючи простір імен незахищеним?

    Відповідь

    Почніть із enforce: baseline, щоб заблокувати найнебезпечніші функції Подів, і додайте warn: restricted плюс audit: restricted, щоб визначити залишок роботи. Потім усуньте проблеми образів, задаючи користувачів, що не є root, виправляючи власника файлів і монтуючи явні шляхи для запису, як-от emptyDir для /var/cache. Після розв’язання попереджень і тестування розгортань підніміть примусове застосування до restricted. Цей поетапний підхід поліпшує безпеку негайно, водночас уникаючи великого збою.

  8. Розбір інциденту виявляє, що скомпрометований Под застосунку міг створювати файли всередині своєї файлової системи образу контейнера, працювати від імені root і використовувати типові можливості. Застосунок не використовував простори імен хоста чи привілейований режим. Які засоби посилення ви додали б першими, і як вони зменшують вплив після компрометації?

    Відповідь

    Додайте виконання не від імені root із runAsNonRoot: true та ненульовим runAsUser, задайте readOnlyRootFilesystem: true з явними томами для запису, відкиньте всі можливості, задайте allowPrivilegeEscalation: false і використайте seccompProfile: RuntimeDefault. Ці засоби контролю не виправляють початкову вразливість застосунку, але вони зменшують те, що зловмисник може зробити після виконання коду. Зловмисник має менше повноважень над процесами, менше привілеїв ядра, менше розташувань для закріплення з можливістю запису та вужчу поверхню syscall.

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

Розділ «Практична вправа: аналіз безпеки та усунення проблем»

Сценарій: Команда просить вас затвердити наведений Под для простору імен застосунків. Простір імен наразі примусово застосовує baseline і попереджає про restricted. Ваше завдання — проаналізувати маніфест, передбачити, які налаштування створюють проблеми допуску чи попередження, а потім створити безпечнішу заміну, що зберігає вимогу застосунку писати тимчасові файли.

apiVersion: v1
kind: Pod
metadata:
name: web-app
namespace: production
spec:
hostNetwork: true
hostPID: true
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 80
securityContext:
runAsUser: 0
privileged: true
readOnlyRootFilesystem: false
allowPrivilegeEscalation: true
capabilities:
add:
- SYS_ADMIN

Крок 1: класифікуйте кожен ризик

Розділ «Крок 1: класифікуйте кожен ризик»

Прочитайте маніфест згори донизу й класифікуйте кожне ризиковане поле як одну з трьох категорій: ризик межі хоста, ризик підвищення привілеїв або ризик операційної гігієни. Не переходьте одразу до фінального YAML. Уміння, яке ви практикуєте, — це міркування під час перегляду: визначте механізм, поясніть шкоду й лише потім оберіть виправлення.

ПроблемаКатегоріяРизикБезпечніший напрямок
hostNetwork: trueМежа хостаСпільно використовує мережевий простір імен вузла й може створювати ризики видимості трафіку чи конфлікту портівПрибрати для звичайних застосунків; використати Сервіс
hostPID: trueМежа хостаРозкриває інформацію про процеси хоста й можливі шляхи втручання в процесиПрибрати для звичайних застосунків
runAsUser: 0ПривілейПрацює від імені root усередині контейнераВикористати ненульовий UID і runAsNonRoot: true
privileged: trueПривілейНадає широкий доступ до пристроїв хоста й можливостейУстановити false або опустити
readOnlyRootFilesystem: falseЗакріпленняДозволяє запис до файлової системи образуУстановити true й змонтувати явні шляхи для запису
allowPrivilegeEscalation: trueПривілейДозволяє підвищення в стилі setuidУстановити false
SYS_ADMINПривілейНадає широку можливість адміністрування ядраВідкинути всі можливості; уникати, якщо немає глибокого обґрунтування
image: myapp:latestГігієнаЗмінний тег робить перегляд і відкат менш передбачуванимиВикористати незмінний тег версії чи дайджест
containerPort: 80Тиск дизайнуМоже заохочувати непотрібні привілеї малого портуСлухати на 8080 й надавати порт 80 через Сервіс

Крок 2: передбачте результат PSA

Розділ «Крок 2: передбачте результат PSA»

У просторі імен із enforce: baseline цей Под має бути відхилено, бо він використовує простори імен хоста, привілейований режим і небезпечну можливість. У просторі імен лише з warn: restricted він також видавав би попередження про виконання від імені root та інші прогалини посилення. Запишіть, які поля є блокерами baseline, перш ніж перевіряти відповідь, бо це передбачення — та частина, що будує іспитове й операційне судження.

Крок 3: створіть посилений Под

Розділ «Крок 3: створіть посилений Под»

Виправлена версія нижче припускає, що застосунок може слухати на 8080 і потребує запису до /tmp плюс /var/cache/app. Якщо вашому реальному застосунку потрібні інші шляхи для запису, збережіть той самий патерн і змініть лише шляхи монтування. Важливий дизайн полягає в тому, що записи є явними, а не розкиданими по файловій системі образу.

apiVersion: v1
kind: Pod
metadata:
name: web-app
namespace: production
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp@sha256:abc123def456
ports:
- containerPort: 8080
securityContext:
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
- name: app-cache
mountPath: /var/cache/app
volumes:
- name: tmp
emptyDir: {}
- name: app-cache
emptyDir: {}

Крок 4: додайте Сервіс замість прив’язування контейнера до малого порту

Розділ «Крок 4: додайте Сервіс замість прив’язування контейнера до малого порту»

Якщо клієнтам потрібен порт 80, надавайте цей порт на рівні Сервісу, а контейнер нехай слухає на високому порту. Так ви уникаєте надання дозволів на прив’язування до малого порту всередині контейнера й зберігаєте сумісність Пода із суворішими налаштуваннями безпеки.

apiVersion: v1
kind: Service
metadata:
name: web-app
namespace: production
spec:
selector:
app: web-app
ports:
- name: http
port: 80
targetPort: 8080

Крок 5: контрольний список перевірки

Розділ «Крок 5: контрольний список перевірки»
  • Я визначив щонайменше вісім проблем безпеки чи гігієни в оригінальному маніфесті й зіставив кожну з конкретним ризиком.
  • Я пояснив, які оригінальні поля було б заблоковано примусовим застосуванням baseline і які все одно мали б значення для міграції до restricted.
  • Я прибрав спільне використання просторів імен хоста з Пода застосунку замість переміщення всього простору імен застосунку до privileged.
  • Я замінив виконання від імені root ненульовим UID і додав runAsNonRoot: true.
  • Я зберіг readOnlyRootFilesystem: true і надав явні томи для запису для шляхів часу виконання застосунку.
  • Я відкинув усі можливості Linux і не додавав широких можливостей на кшталт SYS_ADMIN.
  • Я задав allowPrivilegeEscalation: false та seccompProfile.type: RuntimeDefault.
  • Я використав Сервіс для надання порту 80, тримаючи контейнер на високому порту.
Проблеми безпеки та виправлення
ПроблемаРизикВиправлення
runAsUser: 0Процес працює від імені root усередині контейнераВикористати runAsUser: 1000 та runAsNonRoot: true
privileged: trueКонтейнер отримує широкий доступ рівня хостаУстановити privileged: false або опустити поле
readOnlyRootFilesystem: falseЗловмисник може змінювати файли всередині файлової системи образуУстановити readOnlyRootFilesystem: true й змонтувати явні томи для запису
allowPrivilegeEscalation: trueШляхи підвищення в стилі setuid залишаються доступнимиУстановити allowPrivilegeEscalation: false
hostNetwork: trueПод спільно використовує мережевий простір імен вузлаПрибрати його й надавати трафік через Сервіс
hostPID: trueПод може бачити процеси хостаПрибрати його для звичайних застосунків
capabilities.add: ["SYS_ADMIN"]Под отримує широку можливість високого ризикуВідкинути всі можливості (ALL) і уникати широких додавань
image: myapp:latestПереглянутий образ може змінитися без зміни маніфестуВикористати незмінну версію чи дайджест
Відсутній профіль seccomp ПодаПоду може бракувати фільтрації syscall часу виконання, яку очікує restrictedЗадати seccompProfile.type: RuntimeDefault
Відсутні явні томи для записуУвімкнення кореневої файлової системи лише для читання може зламати записи часу виконанняДодати emptyDir лише там, де застосунок мусить писати

Безпечна версія не є «безпечною назавжди» лише тому, що маніфест виглядає краще. Їй усе одно потрібні звичайні операційні засоби контролю, як-от сканування образів, RBAC, NetworkPolicy, логування та оновлення. Безпека Подів зменшує радіус ураження, коли щось інше відмовляє.

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

Засіб контролюПризначенняБезпечне налаштування
runAsNonRootЗапобігти випадковому виконанню від імені roottrue
runAsUserЗробити ідентичність часу виконання явноюНенульовий UID
readOnlyRootFilesystemЗменшити втручання та закріпленняtrue з явними томами для запису
allowPrivilegeEscalationБлокувати підвищення в стилі setuidfalse
privilegedУникати широкого доступу рівня хостаfalse або опущено
capabilitiesОбмежити привілеї Linuxdrop: ["ALL"], додавати лише вузькі винятки
seccompProfileФільтрувати ризиковані syscall’иRuntimeDefault
hostNetwork, hostPID, hostIPCУникати спільного використання просторів імен хостаfalse або опущено

Використовуйте Pod Security Standards як спільну мову. privileged — для довірених системних робочих навантажень, яким справді потрібен доступ рівня хоста. baseline — корисна мінімальна планка, що блокує поширені шляхи підвищення привілеїв. restricted — ціль для добре посилених робочих навантажень застосунків. Використовуйте мітки Pod Security Admission, щоб застосовувати, попереджати та проводити аудит цих стандартів на межі простору імен.

Хід рівня сеньйора — це не запам’ятовування ідеального блоку YAML. Це запитання, чому дозвіл потрібен, вибір найменшого механізму, що задовольняє потребу, та обмеження винятків так, щоб вони не ставали типовими для всіх інших.

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