Kubernetes v1.33: Як працює політика завантаження образів

Вступ
Після більш ніж десятирічного використання Kubernetes нарешті усуває одну з найстаріших вразливостей у безпеці у версії v1.33: поведінку imagePullPolicy
, яку ви завжди очікували. Проблема, що виникла у #18787 у 2014 році, полягала в тому, що кластери дозволяли подам повторно використовувати приватні образи на вузлі без перевірки облікових даних після початкового завантаження. Сьогоднішнє альфа-реліз вирішує цю проблему, зв’язуючи записи кешу образів з обліковими даними, специфічними для кожного пода. Ця зміна, ініційована SIG Auth та SIG Node, значно підвищує безпеку реєстрів контейнерів без втрати продуктивності.
Примітка:
У цій статті термін “облікові дані пода” відноситься до аутентифікаційного навантаження — таких як базова аутентифікація, токени OAuth або токени службових облікових записів, доступних поду під час завантаження образів.
IfNotPresent, навіть якщо я не повинен цього мати
До версії v1.33 політика IfNotPresent
виконувала те, що її назва й обіцяла: пропускала завантаження, якщо образ вже існує локально. Однак вона ніколи не перевіряла, чи був запитуючий под спочатку авторизований для завантаження цього образу. Розгляньмо такий сценарій:
- Под A у Namespace X використовує
imagePullSecrets: Secret-foo
для аутентифікації в приватному реєстрі та завантажуєregistry.example.com/foo:latest
. - Под B у Namespace Y, запланований на тому ж вузлі, оголошує
imagePullPolicy: IfNotPresent
, але не надає жодних секретів. - Кублет бачить образ, кешований з пода A, і запускає под B з тим же образом — без перевірки облікових даних.
Таким чином, будь-який под на вузлі міг успадкувати приватні образи, як тільки вони зберігалися на диску. Для суворо регульованих середовищ (PCI-DSS, HIPAA) або багатокористувацьких кластерів це горизонтальне розповсюдження чутливих програмних артефактів було неприйнятним.
IfNotPresent, але лише якщо я повинен це мати
З виходом Kubernetes v1.33 та альфа-функцією KubeletEnsureSecretPulledImages
поведінка змінюється:
- При пропуску кешу Кублет завантажує образ, використовуючи точні облікові дані з
imagePullSecrets
, так само, як і раніше. - При попаданні в кеш Кублет тепер перевіряє, чи облікові дані вхідного пода відповідають хешу або джерельному секрету початкового завантаження.
- Якщо вони збігаються, кешований образ надається негайно. Якщо ні, Кублет відмовляється постачати образ або намагається завантажити його знову, залежно від політики.
На технічному рівні файлова запис на кожному вузлі відображає дайджести образів на хеші облікових даних (SHA-256 Dockerconfig JSON або проекційний токен облікових даних). Коли поди повторно використовують той же об’єкт секрету або ідентичні облікові дані, новий процес аутентифікації не запускається — навіть якщо вміст секрету змінюється, механізм оновлення хешу підтримує дійсність кеш-запису.
Ніколи не завантажувати, але використовувати, якщо авторизовано
Політика Never
також отримала оновлення безпеки. У попередніх релізах imagePullPolicy: Never
просто вказувала Кублету не звертатися до жодного реєстру. У версії v1.33+: перш ніж запустити контейнер, Кублет перевіряє, чи под надає облікові дані, що відповідають зафіксованому завантаженню. Неавторизовані поди повинні надати дійсні облікові дані, інакше вони отримують помилку “образ не знайдено”.
Завжди завантажувати, якщо авторизовано
Політика Always
довгий час вимагала аутентифікації при кожному завантаженні, за замовчуванням завантажуючи лише маніфест. Хоча це забезпечує безпеку, воно ставило реєстри контейнерів у критичний шлях під час розгортання та перезавантажень. Завдяки новому кешу навіть Always
може прозоро підтвердити, що облікові дані пода відповідають останньому завантаженню, не завантажуючи шари знову, що покращує час запуску та зберігає можливість аудиту.
Як це працює
KEP-2535 визначає просту, локальну для вузла автоматизовану систему. Загальний процес виглядає так:
- Под запитує образ ↑ не на диску → записати файл “наміри” з ім’ям образу та хешованими обліковими даними.
- Кублет виконує завантаження через CRI (плагін containerd або CRI-O), використовуючи надані облікові дані.
- У разі успіху записати запис “успішного завантаження”: дайджест образу, хеш облікових даних, UID секрету, мітка часу.
- Видалити файл “наміри”, зберігши затверджений запис безстроково (або до ручного збору сміття).
- Майбутні поди → якщо образ існує, порівняти хеш облікових даних + UID секрету; при збігу повторно використовувати локально без звернення до реєстру.
- При невідповідності або неуспіх (для
Never
/IfNotPresent
), або завантажити знову (Always
).
Оскільки всі дані зберігаються в /var/lib/kubelet/image-credential-cache/
, не робиться жодних додаткових викликів до etcd або API-сервера. Цей дизайн робить функцію одночасно надійною та ефективною.
Сумісність з CRI-реалізаціями
На технічному рівні Kubernetes покладається на Інтерфейс виконання контейнерів (CRI) для управління завантаженням образів. Версія v1.33 розширює як containerd
(v1.6+), так і CRI-O
(v1.24+), щоб передавати хеші облікових даних через шиму виконання. Член громади Стеф Войттек з проекту CRI-O зазначає: “Ми додали новий AuthZ хук у CRI-O, який розпізнає записи намірів Кублету, що забезпечує відсутність викликів до реєстру, коли хеші збігаються.” Спадкова dockershim Docker все ще отримує вигоду, але користувачів заохочують переходити на нативні реалізації CRI для повного охоплення функцій.
Безпекові наслідки та модель загроз
Зв’язавши записи кешу образів з конкретними обліковими даними, версія v1.33 закриває бічний вектор атаки: скомпрометований под на вузлі N більше не може обманути Кублет, щоб він надав приватний образ, завантажений несумісним навантаженням. Це вдосконалення відповідає найкращим практикам з аудиту безпеки CNCF (2021) та вирішує проблему CVE-2022-31620, яка вказувала на несанкціоноване повторне використання образів. У багатокористувацьких кластерах адміністратори тепер можуть гарантувати ізоляцію приватних образів для кожного пода без використання мережевих політик або вебхуків допуску.
Продуктивність і накладні витрати
Початкові бенчмарки на тестовій інфраструктурі Kubernetes показують пошук облікових даних за підмілісекунди на файлових системах ext4 під час 50 одночасних запитів. Навіть на вузлах з HDD пошуки залишаються менше 5 мс, що є 70% покращенням порівняно з попереднім підходом лише з Always
. SIG Node працює над шаром кешу в пам’яті (KEP-3067), щоб ще більше зменшити затримки до мікросекундного масштабу, що критично для навантажень з переривчастим характером, таких як CI/CD пайплайни або сценарії обчислень на краю.
Що далі?
У перспективі версії v1.34 та далі:
- Інтеграція з Проектованими токенами службових облікових записів для постачальників облікових даних з Kubelet, що дозволить використовувати короткоживучі, специфічні для навантаження облікові дані.
- Розробка формальної системи бенчмарків під егідою SIG Scalability для кількісної оцінки продуктивності та споживання ресурсів.
- Введення рівня кешування в пам’яті для виключення дискового вводу-виводу при перевірці облікових даних.
- Додавання підтримки терміну дії облікових даних та примусової повторної валідації, що охоплює випадки використання, такі як ротація токенів AWS ECR або короткоживучі токени OAuth GCR.
Як долучитися
Щоб дізнатися більше, почніть з KEP-2535 та офіційного посібника з концепцій. Приєднуйтесь до SIG Auth та SIG Node на Slack (slack.k8s.io) у каналах #sig-auth-authenticators-dev
або #sig-node
, а також беріть участь у їх двотижневих зустрічах, які зазначені в README SIG Auth. Ваші відгуки та внески в код вітаються — давайте забезпечимо безпеку завантаження образів для всіх!
Джерело: Блог Kubernetes