# Kubernetes v1.37: Захист зберігання контейнерів через параметри bind mount та режими EmptyDir

LLMS index: [llms.txt](/llms.txt)

---

Kubernetes v1.37 приносить важливі функції безпеки зберігання: режими дозволів `emptyDir` та параметри bind mount. Вони допомагають розробникам застосунків та фахівцям з безпеки впроваджувати суворі політики безпеки, наприклад, забороняти видалення файлів між контейнерами або виконання довільних бінарних файлів із томів з правами запису, безпосередньо в Kubernetes без будь-яких складних обхідних шляхів.

## Основи Linux: зберігання та дозволи {#linux-storage-and-permission-fundamentals}

Перш ніж заглибитись у нові функції Kubernetes, коротко оглянемо низькорівневі механізми безпеки Linux, які роблять їх можливими.

### Прапорці bind mount {#bind-mount-flags}

Коли Linux монтує або повторно монтує теку, прапорці Virtual File System (VFS) контролюють, які дії дозволені в цій файловій системі:

- **`noexec`**: Не дозволяє безпосереднє виконання будь-яких бінарних файлів у змонтованій файловій системі.
- **`nosuid`**: Не дозволяє бітам set-user-identifier або set-group-identifier діяти.
- **`nodev`**: Не інтерпретує символічні або блокові спеціальні пристрої у файловій системі.

### Дозволи теки та sticky-біт {#directory-permissions-and-the-sticky-bit}

Стандартні Unix-дозволи регулюють доступ у трьох областях: Власник, Група та Інші (наприклад, `0755` або `0777`).

Окрім стандартних бітів читання, запису та виконання, Linux підтримує *sticky-біт* (як у режимі `01777`). Коли sticky-біт застосовується до теки, він гарантує, що файл у цій теці може бути видалений або перейменований лише власником файлу або root. Це є необхідним для спільних тек з правом на запис, таких як `/tmp`.

## Причини для вдосконалень {#motivation-for-the-improvements}

Чому Kubernetes потребує параметри bind mount та дозволів `emptyDir`?

Основна мета цих функцій — підвищити безпеку робочих навантажень Kubernetes, дозволяючи параметри bind mount, повʼязані з безпекою, при монтуванні томів. Стандартно том монтується як bind mount у контейнери середовищем виконання контейнерів та kubelet без прапорців `noexec`, `nosuid` або `nodev`. Це стандартне значення може підривати безпеку. Наприклад, без `noexec`, скомпрометований процес може використовувати будь-який том з правами на запис (`emptyDir`, PersistentVolume тощо) для завантаження, `chmod +x` та виконання довільних бінарних файлів, навіть коли контейнер має право тільки для читання кореневої файлової системи (`readOnlyRootFilesystem: true`). Підтримка `noexec`, `nodev` та `nosuid` надає користувачам вбудований спосіб посилення монтування томів відповідно до стандартів безпеки та політик.

Проблема найбільш помітна з томами `emptyDir`, які є найпоширенішим типом тому з правом на запис та були предметом кількох повідомлень про проблеми з безпекою:

- [Issue #48912](https://github.com/kubernetes/kubernetes/issues/48912): Визнано прогалину в безпеці — нездатність встановити параметри монтування для `emptyDir` була виявлена під час аудиту, але залишилася невирішеною до теперішнього часу.
- [Issue #119627](https://github.com/kubernetes/kubernetes/issues/119627): Аудит безпеки Kubernetes 1.24 (Finding NCC-E003660-7HM) — зовнішній аудит спеціально зазначав, що нездатність монтувати `emptyDir` з `noexec` являє собою збій в безпеці.

Однак та ж прогалина стосується всіх типів томів. У PersistentVolumes є поле `mountOptions`, але ці параметри є прапорцями рівня файлової системи, які застосовуються CSI-драйвером на вузлі, тому вони не надійно перетворюються на прапорці bind mount всередині контейнера. Раніше не було механізму для встановлення `noexec`, `nosuid` або `nodev` на bind mount, який створює середовище виконання контейнерів для будь-якого типу тому.

Крім того, тип тому `emptyDir` зазвичай створює теки з жорстко заданим режимом `0777`. Раніше це означало, що **будь-який** процес, який може знайти том, може читати, записувати та видаляти все в томі, незалежно від того, хто його створив.

Ви могли, і все ще можете, використовувати init-контейнер для встановлення іншого режиму доступу, але це складніше і важче перевірити на відповідність вимогам.

Це викликає реальні проблеми:

- Контейнери в Podʼах, які діляться `emptyDir`, не можуть запобігти видаленню файлів одного контейнера іншим. Sticky-біт (`01777`) вирішує цю проблему, але не було вбудованого способу його встановити.
- Деякі застосунки та фреймворки безпеки очікують, що теки `/tmp` мають встановлений sticky-біт (режим `01777`). Без вбудованої підтримки встановлення режиму `emptyDir` користувачам доводилося використовувати init-контейнери або альтернативні типи томів, щоб задовольнити це вимогу.
- Інженерам платформ, які бажають більш суворі дозволи (наприклад, `0750` лише для власника та групи), доводилося використовувати init-контейнери з `chmod`, що додає зайву складність.

Тип тому `emptyDir` був помітною прогалиною. Як один із найпоширеніших типів томів з можливістю запису у Kubernetes, він не мав жодного способу контролювати свої дозволи створення.

## Приклади використання в реальних умовах {#real-world-use-cases}

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

**Запобігання розширенню прав доступу на монтованих розділах із можливістю запису**: Розробник застосунку, який налаштовує тимчасові робочі томи (як `emptyDir` або монтування `/tmp`), може переконатися, що вони монтуються з `nosuid` та `noexec`. Це гарантує, що навіть якщо застосунок скомпрометовано та завантажено зловмисне навантаження, робоче навантаження не може виконати це навантаження або використати його для підвищення привілеїв на вузлі.

**Захист спільного тимчасового простору в Podʼах з кількома контейнерами**: Розробник, який налаштовує Podʼи CI/CD конвеєри, часто потребує кількох контейнерів (наприклад, контейнера збірки та sidecar логгера) для спільного робочого простору. Встановивши `mode: 01777` на `emptyDir`, розробник гарантує, що спільний робочий простір працює як традиційна Unix-тека `/tmp`. Кожен контейнер може незалежно записувати файли, але скомпрометований процес в одному контейнері не може видалити артефакти збірки, створені іншим.

**Впровадження принципу найменшого привілею для даних застосунку**: Розробник застосунку, який розгортає Pod бази даних, може заблокувати доступ до тимчасового сховища бази даних. Встановивши `mode: 0750` на `emptyDir`, розробник гарантує, що лише конкретний користувач та група бази даних можуть читати або записувати до тому, явно відмовляючи в доступі до будь-яких інших процесів або sidecar контейнерів у тому самому Podʼі.

**Примітка**: Обидві функції знаходяться за Alpha-функціональними можливостями в Kubernetes v1.37. Для їх використання увімкніть `VolumeBindMountOptions` та `EmptyDirVolumeMode` на API-сервері та kubelet.

## Приклад 1: Впровадження параметрів bind mount {#example-1-enforcing-bind-mount-options}

Цей повний маніфест Podʼа монтує том `emptyDir` у `/tmp` з `bindMountOptions: [noexec, nosuid]`.

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: hardened-bindmount-pod
  namespace: default
spec:
  os:
    name: linux
  containers:
    - name: hardened-app
      image: alpine:latest
      command: ["sleep", "3600"]
      securityContext:
        readOnlyRootFilesystem: true
      volumeMounts:
        - name: temp-storage
          mountPath: /tmp
          bindMountOptions:
            - noexec
            - nosuid
  volumes:
    - name: temp-storage
      emptyDir: {}
```

## Приклад 2: Режим дозволів тому `emptyDir` зі sticky-бітом {#example-2-emptydir-volume-permission-mode-with-sticky-bit}

Цей повний маніфест Podʼа створює том `emptyDir` із використанням `mode: 01777` для впровадження стандартних захисних механізмів Unix sticky-біту `/tmp` між контейнерами.

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: hardened-emptydir-pod
  namespace: default
spec:
  os:
    name: linux
  containers:
    - name: app-container
      image: alpine:latest
      command: ["sleep", "3600"]
      volumeMounts:
        - name: shared-tmp
          mountPath: /tmp
  volumes:
    - name: shared-tmp
      emptyDir:
        mode: 01777
```

## Перевірка функцій у Linux {#verifying-the-features-in-linux}

Щоб перевірити, що ці функції активно впроваджують обмеження, ви можете виконати `kubectl exec` у контейнері. Наведені нижче приклади імітують спроби виконати дії, які ці функції успішно блокують.

### Перевірка noexec {#verifying-noexec}

Спроба запису та виконання скрипту на тому, змонтованому з `noexec`:

```shell
# 1. Виконайте exec у podʼі
kubectl exec -it hardened-bindmount-pod -- sh

# 2. Створіть виконуваний скрипт на змонтованому томі
cd /tmp
echo '#!/bin/sh' > test.sh
echo 'echo "Executing untrusted code..."' >> test.sh
chmod +x test.sh

# 3. Спроба виконати скрипт
./test.sh
```

Очінуваний результат:

```none
sh: ./test.sh: Permission denied
```

Навіть якщо виконуваний файл створено, ядро Linux відмовляє у виконанні, оскільки `MS_NOEXEC` впроваджується на рівні bind mount.

### Перевірка sticky-біту {#verifying-the-sticky-bit}

Спроба видалення файлу іншого користувача в `emptyDir` із режимом дозволів `01777`:

```shell
# 1. Виконайте exec у podʼі
kubectl exec -it hardened-emptydir-pod -- sh

# 2. Перевірте дозволи теки /tmp
ls -ld /tmp
# Вивід: drwxrwxrwt 2 root root ... /tmp (Зверніть увагу на 't', що вказує на sticky-біт)

# 3. Створіть файл як користувач guest
su -s /bin/sh -c "touch /tmp/guest_file" guest

# 4. Спроба видалити цей файл як nobody
su -s /bin/sh -c "rm /tmp/guest_file" nobody
```

Очікуваний результат:

```none
rm: can't remove '/tmp/guest_file': Operation not permitted
```

Ядро блокує видалення, оскільки sticky-біт (`01777`) обмежує видалення файлів суворо власником файлу.

## Важливі деталі {#things-to-know}

Починаючи користуватися цими функціями, майте на увазі ці ключові моменти. Повні деталі доступні в офіційній документації для [параметрів bind mount](/docs/tasks/configure-pod-container/configure-bind-mount-options/), [режиму тому `emptyDir`](/docs/tasks/configure-pod-container/configure-emptydir-volume-mode/) та [томів `emptyDir`](/docs/concepts/storage/volumes/#emptydir).

- **Стандартноне змінено**: Якщо ви пропускаєте `bindMountOptions` або не встановлюєте `mode` для `emptyDir`, ви отримуєте стандартну поведінку (як-от дозволи `0777`) точно так само, як і раніше.
- **Широка підтримка томів**: `bindMountOptions` працює з `emptyDir`, PersistentVolumes, CSI-томами, проєкційними томами, ConfigMap, Secret та іншими. Єдиним винятком є томи образів, які явно не підтримуються. Поле `mode` працює з усіма типами середовища `emptyDir`: default (на основі диска), `Memory` (tmpfs) та `HugePages`.
- **Можливості середовища виконання мають значення (для `bindMountOptions`)**: Контейнерне середовище виконання **повинно** підтримувати поле CRI `mount_options` та оголошувати це через `runtimeFeatures`. Планувальник використовує *оголошені вузлом можливості*, щоб уникати розміщення Podʼів на несумісних вузлах. Якщо Pod все ж досягає такого вузла, kubelet відхиляє його. Немає мовчазного зниження якості. Однак використання `mode` для `emptyDir` не потребує підтримки середовища виконання.
- **Не те саме, що PV mountOptions**: `mountOptions` PersistentVolume застосовуються на рівні сховища через CSI-драйвер. Нові `bindMountOptions` контролюють прапорці bind mount, які застосовуються всередині контейнера середовищем виконання. Вони працюють на різних рівнях і не конфліктують.
- **Взаємодія fsGroup**: Якщо `fsGroup` встановлено в контексті безпеки Podʼа, дозволи групи, які застосовуються `fsGroup`, перевищать `mode`, вказаний для тому `emptyDir`. Це та сама поведінка, що існує для `defaultMode` на томах Secret та ConfigMap.
- **Тільки Linux**: Прапорці на кшталт `noexec`, `nosuid`, `nodev` та Unix-дозволи є концепціями Linux. `bindMountOptions` не має ефекту на вузлах Windows. На Windows поле `mode` також пропускається для томів `emptyDir`, оскільки Windows не підтримує Unix-дозволи на файли.
- **Безпека при розбіжності версій**: Обидві функції є додатковими. Для `emptyDir` `mode`: якщо API-сервер має цвімкнуті функціональні можливості, але kubelet — ні, поле приймається, але ігнорується — kubelet повертається до `0777`. Для `bindMountOptions`: планувальник використовує Node Declared Features, щоб запобігти розміщенню Podʼів на вузлах без підтримки середовища виконання; якщо Pod досягає такого вузла, kubelet відхиляє його, а не ігнорує параметри мовчки.
- **Функціональні можливості**: Обидві можливості доступні як Alpha-функції в Kubernetes v1.37:
  - `VolumeBindMountOptions`: Контролює прапорці bind mount при монтуванні томів.
  - `EmptyDirVolumeMode`: Контролює режими дозволів створення на томах `emptyDir`.

## Як долучитись? {#how-do-i-get-involved}

Ці нові функції розробляють [SIG Node](https://www.kubernetes.dev/community/community-groups/sigs/node/) та [SIG Storage](https://www.kubernetes.dev/community/community-groups/sigs/storage/). Ви можете знайти більше деталей у KEP для цих покращень: [KEP-5855](https://www.kubernetes.dev/resources/keps/5855/) (параметри bind mount) та [KEP-5502](https://www.kubernetes.dev/resources/keps/5502/) (режим дозволів `emptyDir`).

Звʼяжіться з SIG Node:

- Slack: [#sig-node](https://kubernetes.slack.com/messages/sig-node)
- [Список розсилки](https://groups.google.com/forum/#!forum/kubernetes-sig-node)

Звʼяжіться з SIG Storage:

- Slack: [#sig-storage](https://kubernetes.slack.com/messages/sig-storage)
- [Список розсилки](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)
