Kubernetes v1.35: Кращий спосіб передачі токенів ServiceAccount до драйверів CSI
Якщо ви підтримуєте драйвер CSI, який використовує токени ServiceAccount, Kubernetes v1.35 приносить удосконалення, про яке вам варто знати. З моменту введення можливості TokenRequests, токени ServiceAccount, запитувані драйверами CSI, передавалися їм через поле volume_context. Хоча це працювало, це не ідеальне місце для конфіденційної інформації, і ми бачили випадки, коли токени випадково потрапляли в логи драйверів CSI.
Kubernetes v1.35 вводить рішення бета-версії для вирішення цієї проблеми:
Добровільне ввімкнення драйвером CSI отримання токенів ServiceAccount через поле Secrets.
Це дозволяє драйверам CSI отримувати токени ServiceAccount
через поле secrets у NodePublishVolumeRequest,
яке є відповідним місцем для конфіденційних даних у специфікації CSI.
Розуміння поточного підходу
Коли драйвери CSI використовують можливість TokenRequests, вони можуть запитувати токени ServiceAccount для ідентичності робочого навантаження, налаштовуючи поле TokenRequests у специфікації CSIDriver. Ці токени передаються драйверам як частина мапи атрибутів тому, використовуючи ключ csi.storage.k8s.io/serviceAccount.tokens.
Поле volume_context працює, але воно не призначене для конфіденційних даних. Через це виникають кілька викликів:
По-перше, інструмент protosanitizer, який використовують драйвери CSI, не розглядає контекст тому як конфіденційний, тому токени ServiceAccount можуть потрапити в логи, коли gRPC-запити логуються. Це сталося з CVE-2023-2878 у Secrets Store CSI Driver та CVE-2024-3744 у Azure File CSI Driver.
По-друге, кожен драйвер CSI, який хоче уникнути цієї проблеми, повинен реалізовувати власну логіку санітізації, що призводить до неузгодженості між драйверами.
Специфікація CSI вже має поле secrets у NodePublishVolumeRequest, яке призначене саме для такого роду конфіденційної інформації. Проблема полягає в тому, що ми не можемо просто змінити місце, де ми розміщуємо токени, без порушення роботи поточних драйверів CSI, які очікують їх у контексті тому.
Як працює механізм увімкнення
Kubernetes v1.35 вводить механізм увімкнення, який дозволяє драйверам CSI вибирати, як вони отримують токени ServiceAccount. Таким чином, поточні драйвери продовжують працювати як і раніше, а драйвери можуть перейти до більш відповідного поля secrets, коли будуть готові.
Драйвери CSI можуть встановити нове поле у своїй специфікації CSIDriver:
#
# УВАГА: це приклад конфігурації.
# Не використовуйте це для власного кластера!
#
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: example-csi-driver
spec:
# ... наявні поля ...
tokenRequests:
- audience: "example.com"
expirationSeconds: 3600
# Нове поле для ввімкнення доставки через secrets
serviceAccountTokenInSecrets: true # типово false
Поведінка залежить від поля serviceAccountTokenInSecrets:
Коли встановлено false (типово), токени розміщуються у VolumeContext з ключем csi.storage.k8s.io/serviceAccount.tokens, як і сьогодні.
Коли встановлено true, токени розміщуються лише у полі Secrets з тим самим ключем.
Про бета-реліз
Функціональна можливість CSIServiceAccountTokenSecrets типово увімкнена як для kubelet, так і для kube-apiserver. Оскільки поле serviceAccountTokenInSecrets типово має значення false, увімкнення функціональної можливості не змінює жодної поточної поведінки. Усі драйвери продовжують отримувати токени через контекст тому, якщо вони явно не ввімкнуть нову поведінку. Це пояснює, чому ми почувалися комфортно, починаючи з бета-версії, а не альфа.
Посібник для авторів драйверів CSI
Якщо ви підтримуєте драйвер CSI, який використовує токени ServiceAccount, ось як запровадити цю можливість.
Додавання резервної логіки
Спочатку оновіть код вашого драйвера, щоб перевіряти обидва місця на наявність токенів. Це робить ваш драйвер сумісним з обома підходами, старим і новим:
const serviceAccountTokenKey = "csi.storage.k8s.io/serviceAccount.tokens"
func getServiceAccountTokens(req *csi.NodePublishVolumeRequest) (string, error) {
// Перевірити поле secrets спочатку (нова поведінка, коли драйвер увімкнув її)
if tokens, ok := req.Secrets[serviceAccountTokenKey]; ok {
return tokens, nil
}
// Повернення до контексту тому (поточна поведінка)
if tokens, ok := req.VolumeContext[serviceAccountTokenKey]; ok {
return tokens, nil
}
return "", fmt.Errorf("service account tokens not found")
}
Ця резервна логіка є зворотно сумісною та безпечною для випуску в будь-якій версії драйвера, навіть до оновлення кластерів до v1.35.
Послідовність розгортання
Автори драйверів CSI повинні дотримуватися певної послідовності під час впровадження цієї можливості, щоб уникнути порушення наявних томів.
Підготовка драйвера (може відбутися будь-коли)
Ви можете почати підготовку вашого драйвера прямо зараз, додавши резервну логіку, яка перевіряє як поле secrets, так і контекст тому на наявність токенів. Ця зміна коду є зворотно сумісною та безпечною для випуску в будь-якій версії драйвера, навіть до оновлення кластерів до v1.35. Ми заохочуємо вас додати цю логіку раніше, випускати релізи та навіть переносити її (backport) до гілок обслуговування, де це можливо.
Оновлення кластера та увімкнення можливості
Після того, як ваш драйвер має резервну логіку, ось безпечний порядок розгортання для увімкнення можливості в кластері:
- Завершити оновлення kube-apiserver до 1.35 або пізнішої версії
- Завершити оновлення kubelet до 1.35 або пізнішої версії на всіх вузлах
- Переконатися, що версія драйвера CSI з резервною логікою розгорнута (якщо не зроблено в фазі підготовки)
- Повністю завершити розгортання DaemonSet драйвера CSI на всіх вузлах
- Оновити ваш маніфест CSIDriver, щоб встановити
serviceAccountTokenInSecrets: true
Важливі обмеження
Найважливіше, що потрібно памʼятати, — це порядок у часі. Якщо ваш DaemonSet драйвера CSI та обʼєкт CSIDriver знаходяться в одному маніфесті або чарті Helm, вам потрібно два окремі оновлення. Спочатку розгорніть нову версію драйвера з резервною логікою, зачекайте завершення розгортання DaemonSet, потім оновіть специфікацію CSIDriver, щоб встановити serviceAccountTokenInSecrets: true.
Також не оновлюйте CSIDriver перед тим, як завершиться розгортання всіх Podʼів драйвера. Якщо ви це зробите, монтування томів зазнають невдачі на вузлах, які все ще працюють зі старою версією драйвера, оскільки ті Podʼи перевіряють лише контекст тому.
Чому це важливо
Впровадження цієї можливості допомагає в кількох аспектах:
- Це усуває ризик випадкового потрапляння токенів ServiceAccount у логи як частини контексту тому в gRPC-запитах
- Використовується призначене специфікацією CSI поле для конфіденційних даних, і це правильно
- Інструмент
protosanitizerавтоматично правильно обробляє поле secrets, тому вам не потрібні специфічні для драйвера обхідні шляхи - Це опціонально, тому ви можете мігрувати у власному темпі без порушення наявних розгортань
Заклик до дії
Ми (Kubernetes SIG Storage) заохочуємо авторів драйверів CSI впровадити цю можливість та надати відгуки про досвід міграції. Якщо у вас є думки щодо дизайну API або виникають будь-які проблеми під час впровадження, будь ласка, зверніться до нас у каналі #csi на Kubernetes Slack (для запрошення відвідайте https://slack.k8s.io/).
Ви можете стежити за KEP-5538, щоб відстежувати прогрес у наступних релізах Kubernetes.