Налаштування контексту безпеки для Podʼа або контейнера

Контекст безпеки визначає параметри привілеїв та контролю доступу для Podʼа або контейнера. Налаштування контексту безпеки включають, але не обмежуються:

  • Дискреційний контроль доступу: Дозвіл на доступ до обʼєкта, такого як файл, базується на ідентифікаторі користувача (UID) та ідентифікаторі групи (GID).

  • Security Enhanced Linux (SELinux): Обʼєкти призначаються мітки безпеки.

  • Виконання з привілеями або без них.

  • Linux Capabilities: Надає процесу деякі привілеї, але не всі привілеї користувача root.

  • AppArmor: Використовуйте профілі програм для обмеження можливостей окремих програм.

  • Seccomp: Фільтрує системні виклики процесу.

  • allowPrivilegeEscalation: Контролює, чи може процес отримувати більше привілеїв, ніж його батьківський процес. Ця логічна величина безпосередньо контролює, чи встановлюється прапорець no_new_privs для процесу контейнера. allowPrivilegeEscalation завжди true, коли контейнер:

    • запущений з привілеями, або
    • має CAP_SYS_ADMIN
  • readOnlyRootFilesystem: Підключає кореневу файлову систему контейнера тільки для читання.

Вищевказані пункти не є повним набором налаштувань контексту безпеки,докладну інформацію див. у SecurityContext для повного переліку.

Перш ніж ви розпочнете

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

Для перевірки версії введіть kubectl version.

Встановлення контексту безпеки для Pod

Щоб вказати параметри безпеки для Podʼа, включіть поле securityContext в специфікацію Pod. Поле securityContext є обʼєктом PodSecurityContext. Параметри безпеки, які ви вказуєте для Pod, застосовуються до всіх контейнерів в Podʼі. Ось файл конфігурації для Podʼа з securityContext та томом emptyDir:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox:1.28
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

У файлі конфігурації поле runAsUser вказує, що для будь-яких контейнерів в Podʼі, всі процеси виконуються з ідентифікатором користувача 1000. Поле runAsGroup вказує основний ідентифікатор групи 3000 для усіх процесів у контейнерах Pod. Якщо це поле відсутнє, основний ідентифікатор групи контейнерів буде root(0). Будь-які створені файли також належатимуть користувачу 1000 та групі 3000 при вказанні runAsGroup. Оскільки вказано поле fsGroup, всі процеси контейнера також належать до додаткової групи ідентифікатора 2000. Власником тому /data/demo та всіх створених файлів у цьому томі буде груповий ідентифікатор 2000.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo -- sh

У вашій оболонці перелічіть запущені процеси:

ps

Виведений результат показує, що процеси виконуються від імені користувача 1000, що є значенням runAsUser:

PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 1h
    6 1000      0:00 sh
...

У вашій оболонці перейдіть до /data, та виведіть список тек:

cd /data
ls -l

Виведений результат показує, що тека /data/demo має ідентифікатор групи 2000, що є значенням fsGroup.

drwxrwsrwx 2 root 2000 4096 Jun  6 20:08 demo

У вашій оболонці перейдіть до /data/demo, та створіть файл:

cd demo
echo hello > testfile

Виведіть список файлів у теці /data/demo:

ls -l

Виведений результат показує, що testfile має ідентифікатор групи 2000, що є значенням fsGroup.

-rw-r--r-- 1 1000 2000 6 Jun  6 20:08 testfile

Виконайте наступну команду:

id

Результат буде схожий на цей:

uid=1000 gid=3000 groups=2000

З результату видно, що gid дорівнює 3000, що є таким самим, як поле runAsGroup. Якби поле runAsGroup було пропущено, gid залишився б 0 (root), і процес зміг би взаємодіяти з файлами, які належать групі root(0) та групам, які мають необхідні права групи для групи root (0).

Вийдіть з оболонки:

exit

Налаштування політики зміни дозволів та прав власності тому для Pod

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.23 [stable]

Типово Kubernetes рекурсивно змінює права власності та дозволи для вмісту кожного тому так, щоб вони відповідали значенню fsGroup, вказаному в securityContext Podʼа при підключенні цього тому. Для великих томів перевірка та зміна власності та дозволів може займати багато часу, сповільнюючи запуск Podʼів. Ви можете використовувати поле fsGroupChangePolicy в securityContext для контролю способу, яким Kubernetes перевіряє та керує власністю та дозволами для тому.

fsGroupChangePolicy — fsGroupChangePolicy визначає поведінку зміни власності та дозволів тому перед тим, як він буде використаний в Pod. Це поле застосовується лише до типів томів, які підтримують контроль власності та дозволів за допомогою fsGroup. Це поле має два можливі значення:

  • OnRootMismatch: Змінювати дозволи та права власності тільки у випадку, якщо дозволи та права кореневої теки не відповідають очікуваним дозволам тому. Це може допомогти скоротити час зміни власності та дозволів тому.
  • Always: Завжди змінювати дозволи та права власності тому під час підключення.

Наприклад:

securityContext:
  runAsUser: 1000
  runAsGroup: 3000
  fsGroup: 2000
  fsGroupChangePolicy: "OnRootMismatch"

Делегування зміни прав власності та дозволів тому до драйвера CSI

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.26 [stable]

Якщо ви розгортаєте драйвер Container Storage Interface (CSI), який підтримує VOLUME_MOUNT_GROUP NodeServiceCapability, процес встановлення права власності та дозволів файлу на основі fsGroup, вказаного в securityContext, буде виконуватися драйвером CSI, а не Kubernetes. У цьому випадку, оскільки Kubernetes не виконує жодної зміни права власності та дозволів, fsGroupChangePolicy не набуває чинності, і згідно з вказаним CSI, очікується, що драйвер монтує том з наданим fsGroup, що призводить до отримання тому, який є доступними для читаання/запису для fsGroup.

Встановлення контексту безпеки для контейнера

Для вказання параметрів безпеки для контейнера, включіть поле securityContext в маніфест контейнера. Поле securityContext є обʼєктом SecurityContext. Параметри безпеки, які ви вказуєте для контейнера, застосовуються тільки до окремого контейнера, і вони перевизначають налаштування, зроблені на рівні Podʼа, коли є перетин. Налаштування контейнера не впливають на томи Podʼів.

Ось файл конфігурації для Podʼа з одним контейнером. Як Pod, так і контейнер мають поле securityContext:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  securityContext:
    runAsUser: 1000
  containers:
  - name: sec-ctx-demo-2
    image: gcr.io/google-samples/hello-app:2.0
    securityContext:
      runAsUser: 2000
      allowPrivilegeEscalation: false

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo-2

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-2 -- sh

У вашій оболонці перегляньте запущені процеси:

ps aux

Виведений результат показує, що процеси виконуються від імені користувача 2000. Це значення runAsUser, вказане для контейнера. Воно перевизначає значення 1000, вказане для Pod.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2000         1  0.0  0.0   4336   764 ?        Ss   20:36   0:00 /bin/sh -c node server.js
2000         8  0.1  0.5 772124 22604 ?        Sl   20:36   0:00 node server.js
...

Вийдіть з оболонки:

exit

Встановлення можливостей для контейнера

За допомогою можливостей Linux, ви можете надати певні привілеї процесу, не надаючи всі привілеї користувачеві з правами root. Щоб додати або видалити можливості Linux для контейнера, включіть поле capabilities в розділ securityContext маніфесту контейнера.

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

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: gcr.io/google-samples/hello-app:2.0

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo-3

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-3 -- sh

У вашій оболонці перегляньте запущені процеси:

ps aux

Виведений результат показує ідентифікатори процесів (PID) для контейнера:

USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js

У вашій оболонці перегляньте статус для процесу 1:

cd /proc/1
cat status

Виведений результат показує bitmap можливостей для процесу:

...
CapPrm:	00000000a80425fb
CapEff:	00000000a80425fb
...

Запамʼятайте bitmap можливостей, а потім вийдіть з оболонки:

exit

Далі, запустіть контейнер, який є такий самий, як попередній контейнер, за винятком того, що він має додаткові можливості.

Ось файл конфігурації для Pod, який запускає один контейнер. Конфігурація додає можливості CAP_NET_ADMIN та CAP_SYS_TIME:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/hello-app:2.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-4 -- sh

У вашій оболонці перегляньте можливості для процесу 1:

cd /proc/1
cat status

Виведений результат показує бітову карту можливостей для процесу:

...
CapPrm:	00000000aa0435fb
CapEff:	00000000aa0435fb
...

Порівняйте можливості двох контейнерів:

00000000a80425fb
00000000aa0435fb

У bitmap можливостей першого контейнера біти 12 і 25 не встановлені. У другому контейнері, біти 12 і 25 встановлені. Біт 12 — це CAP_NET_ADMIN, а біт 25 — це CAP_SYS_TIME. Дивіться capability.h для визначень констант можливостей.

Встановлення профілю Seccomp для контейнера

Щоб встановити профіль Seccomp для контейнера, включіть поле seccompProfile в розділ securityContext вашого маніфесту Pod або контейнера. Поле seccompProfile є обʼєктом SeccompProfile, який складається з type та localhostProfile. Допустимі варіанти для type включають RuntimeDefault, Unconfined та Localhost. localhostProfile повинен бути встановлений лише якщо type: Localhost. Він вказує шлях до попередньо налаштованого профілю на вузлі, повʼязаного з розташуванням налаштованого профілю Seccomp kubelet (налаштованого за допомогою прапорця --root-dir).

Ось приклад, який встановлює профіль Seccomp до стандартного профілю контейнера вузла:

...
securityContext:
  seccompProfile:
    type: RuntimeDefault

Ось приклад, який встановлює профіль Seccomp до попередньо налаштованого файлу за шляхом <kubelet-root-dir>/seccomp/my-profiles/profile-allow.json:

...
securityContext:
  seccompProfile:
    type: Localhost
    localhostProfile: my-profiles/profile-allow.json

Призначення міток SELinux контейнеру

Щоб призначити мітки SELinux контейнеру, включіть поле seLinuxOptions в розділ securityContext вашого маніфесту Podʼа або контейнера. Поле seLinuxOptions є обʼєктом SELinuxOptions. Ось приклад, який застосовує рівень SELinux:

...
securityContext:
  seLinuxOptions:
    level: "s0:c123,c456"

Ефективне переозначення обʼєктів SELinux в томах

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.28 [beta]

Стандартно, контейнерне середовище рекурсивно призначає мітку SELinux для всіх файлів на всіх томах Pod. Щоб прискорити цей процес, Kubernetes може миттєво змінити мітку SELinux тому за допомогою параметра монтування -o context=<мітка>.

Щоб скористатися цим прискоренням, мають бути виконані всі ці умови:

  • Feature gate ReadWriteOncePod та SELinuxMountReadWriteOncePod повинні бути увімкнені.
  • Pod повинен використовувати PersistentVolumeClaim з відповідними accessModes та feature gate:
    • Або том має accessModes: ["ReadWriteOncePod"], і властивість включення SELinuxMountReadWriteOncePod увімкнена.
    • Або том може використовувати будь-які інші режими доступу та обидва SELinuxMountReadWriteOncePod та SELinuxMount повинні бути увімкнені.
  • Pod (або всі його контейнери, які використовують PersistentVolumeClaim) повинні мати встановлені параметри seLinuxOptions.
  • Відповідний PersistentVolume повинен бути або:
    • Том, який використовує старі типи томів iscsi, rbd або fc.
    • Або том, який використовує драйвер CSI CSI. Драйвер CSI повинен оголосити, що він підтримує монтування з -o context, встановивши spec.seLinuxMount: true у його екземплярі CSIDriver.

Для будь-яких інших типів томів переозначення SELinux відбувається іншим шляхом: контейнерне середовище рекурсивно змінює мітку SELinux для всіх inodes (файлів і тек) у томі. Чим більше файлів і тек у томі, тим довше відбувається це переозначення.

Управління доступом до файлової системи /proc

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.12 [alpha]

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

  • Промасковані шляхи:

    • /proc/asound
    • /proc/acpi
    • /proc/kcore
    • /proc/keys
    • /proc/latency_stats
    • /proc/timer_list
    • /proc/timer_stats
    • /proc/sched_debug
    • /proc/scsi
    • /sys/firmware
  • Шляхи доступні тільки для читання:

    • /proc/bus
    • /proc/fs
    • /proc/irq
    • /proc/sys
    • /proc/sysrq-trigger

Для деяких Podʼів вам може знадобитися обійти стандартний шлях маскування. Найбільш поширений контекст, коли це потрібно, — це спроба запуску контейнерів у межах контейнера Kubernetes (у межах Podʼа).

Поле procMount в securityContext дозволяє користувачеві запитати, щоб /proc контейнера був Unmasked, або міг бути підмонтований для читання-запису контейнерним процесом. Це також стосується /sys/firmware, який не знаходиться в /proc.

...
securityContext:
  procMount: Unmasked

Обговорення

Контекст безпеки для Pod застосовується до Контейнерів Pod і також до Томів Pod при необхідності. Зокрема, fsGroup та seLinuxOptions застосовуються до Томів наступним чином:

  • fsGroup: Томи, які підтримують управління власністю, модифікуються так, щоб бути власністю та доступними для запису за GID, вказаним у fsGroup. Докладніше див. Документ із проєктування управління власністю томів.

  • seLinuxOptions: Томи, які підтримують мітку SELinux, переозначаються так, щоб бути доступними за міткою, вказаною у seLinuxOptions. Зазвичай вам потрібно лише встановити розділ level. Це встановлює мітку Multi-Category Security (MCS), яку отримують всі Контейнери у Pod, а також Томи.

Очищення

Видаліть Pod:

kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4

Що далі

Змінено June 20, 2024 at 12:44 PM PST: Sync changest from andygol/k8s-website (36d05bc8a1)