Налаштування контексту безпеки для 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 для визначень констант можливостей.
Примітка:
Константи можливостей Linux мають формуCAP_XXX
. Але коли ви перелічуєте можливості у маніфесті вашого контейнера, вам необхідно пропустити частину CAP_
константи. Наприклад, для додавання CAP_SYS_TIME
, включіть SYS_TIME
у ваш список можливостей.Встановлення профілю 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 модуль безпеки SELinux повинен бути завантажений в операційну систему хосту.Ефективне переозначення обʼєктів SELinux в томах
Kubernetes v1.28 [beta]
Примітка:
У Kubernetes v1.27 було введено обмежену ранню форму такої поведінки, яка була застосовна тільки до томів (та PersistentVolumeClaims), які використовують режим доступу ReadWriteOncePod
.
Як альфа-функціонал, ви можете увімкнути feature gate SELinuxMount
, щоб розширити це поліпшення продуктивності на інші види PersistentVolumeClaims, як пояснено докладніше нижче.
Стандартно, контейнерне середовище рекурсивно призначає мітку 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
Примітка:
ВстановленняprocMount
в Unmasked потребує, щоб значення spec.hostUsers
в специфікації Pod було false
. Іншими словами: контейнер, який бажає мати Unmasked /proc
або Unmasked /sys
, також повинен бути у просторі імен користувача. У версіях Kubernetes v1.12 по v1.29 це вимога не дотримувалася.Обговорення
Контекст безпеки для Pod застосовується до Контейнерів Pod і також до Томів Pod при необхідності. Зокрема, fsGroup
та seLinuxOptions
застосовуються до Томів наступним чином:
fsGroup
: Томи, які підтримують управління власністю, модифікуються так, щоб бути власністю та доступними для запису за GID, вказаним уfsGroup
. Докладніше див. Документ із проєктування управління власністю томів.seLinuxOptions
: Томи, які підтримують мітку SELinux, переозначаються так, щоб бути доступними за міткою, вказаною уseLinuxOptions
. Зазвичай вам потрібно лише встановити розділlevel
. Це встановлює мітку Multi-Category Security (MCS), яку отримують всі Контейнери у Pod, а також Томи.
Попередження:
Після вказання мітки MCS для Pod всі Pod з такою міткою можуть отримати доступ до Тома. Якщо вам потрібен захист між Podʼами, вам слід призначити унікальну мітку 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
Що далі
- PodSecurityContext
- SecurityContext
- Посібник з налаштування втулків CRI
- Документ проєктування контекстів безпеки
- Документ проєктування управління власністю
- Допуск PodSecurity
- Документ проєктування AllowPrivilegeEscalation
- Для отримання додаткової інформації про механізми безпеки в Linux дивіться Огляд функцій безпеки ядра Linux (Примітка: деяка інформація може бути застарілою)
- Дізнайтеся більше про Простори імен користувачів для Linux контейнерів.
- Промасковані шляхи в специфікації OCI Runtime