open atlas
↑ К треку
Безопасность облака и инфраструктуры CLOUD · 02 · 05

Секреты в Kubernetes

Секрет Kubernetes — это base64, а не шифрование: открытый текст для любого с etcd, узлом или RBAC-чтением. Почему это важно и как управлять секретами без расползания копий по неймспейсам и логам CI.

CLOUD Senior ◷ 18 min
Уровень
ОсновыJuniorMiddleSenior

Джуниор из вашей команды дебажит падающий под и вставляет манифест в тикет: kubectl get secret db-creds -o yaml. Поле data: — это стена из base64, поэтому он думает, что делиться им безопасно: оно выглядит зашифрованным. Вы декодируете одну строку в уме: cG9zdGdyZXM6Ly9hZG1pbjpodW50ZXIyQA== — это просто postgres://admin:hunter2@. Пароль от боевой базы теперь в комментарии Jira, проиндексирован поиском, доступен каждому подрядчику с правами просмотра. Никакого CVE, никакого эксплойта. Просто base64, принятый за замок.

К концу этого урока вы будете точно знать, почему секрет Kubernetes не зашифрован, кто может его прочитать и как управлять секретами без расползания, превращающего одну утечку в компрометацию всего парка.

Base64 — это кодирование, а не шифрование

Это самое дорогое заблуждение в безопасности Kubernetes, поэтому скажу прямо: base64 — это обратимое перекодирование без ключа. Кто угодно и где угодно может выполнить base64 -d и получить исходные байты обратно. В декодировании не участвует никакого секретного материала — в этом весь смысл base64: он существует, чтобы двоичные данные пережили текстовый канал, а не чтобы их защитить. Называть секрет «зашифрованным» из-за того, что в YAML показано aHVudGVyMg== вместо hunter2, — всё равно что называть окно «запертым», потому что вы заклеили его бумагой.

Что Secret в Kubernetes реально даёт по сравнению с ConfigMap — это операционные, а не криптографические свойства: он помечен так, что по умолчанию не печатается в открытых логах; его можно смонтировать как tmpfs-том (в памяти), а не писать на диск; доступ к нему управляется через RBAC как к отдельному типу ресурса. Это реальные, полезные свойства. Ни одно из них не является конфиденциальностью на диске. Байты лежат в etcd, и по умолчанию они лежат там открытым текстом.

Кто на самом деле может прочитать ваш секрет

Зрелый вопрос — никогда «это base64?», а «какова поверхность чтения?». Секрет открыт удивительно широкому радиусу поражения, и каждый путь — это реальная атака, которую мы видели в постмортемах:

Путь чтенияКто получает доступЧто это останавливает
etcd на дискеЛюбой с узлом, бэкапом или украденным снимком etcdEncryptionConfiguration (KMS-провайдер), а не base64
RBAC get/list secretsЛюбой пользователь/SA с этим глаголом в неймспейсеRBAC по минимуму прав; никогда не выдавать list secrets широко
Смонтирован в подЛюбой, кто может сделать exec в под или прочитать его ФССузить SA; монтировать только то, что нужно нагрузке
Токен дефолтного ServiceAccountСкомпрометированный под, дотянувшийся до API с авто-смонтированными правамиautomountServiceAccountToken: false
Логи CI / GitЛюбой, кто читает лог пайплайна или коммитит манифестВнешнее хранилище секретов; никогда не коммитить отрендеренный Secret

Два пути удивляют людей сильнее всего: etcd на диске и RBAC list secrets. По умолчанию kube-apiserver пишет объекты Secret в etcd без шифрования — поэтому бэкап etcd в S3-бакете или украденный снимок тома — это полный дамп учётных данных. А глагол list для секретов в RBAC катастрофичен именно потому, что возвращает содержимое, а не только имена: единственная слишком широкая Role с list по секретам в неймспейсе отдаёт каждую учётку этого неймспейса тому, кто ею владеет. Это верхняя позиция в OWASP Kubernetes Top 10 не просто так.

Шифрование на диске: включаем замок

Фикс для пути через etcd — это шифрование на диске (encryption at rest), настраиваемое на API-сервере через EncryptionConfiguration. Урок здесь в том, какого провайдера вы выбираете, потому что очевидный вариант — это ловушка.

Ловушка — это провайдеры aescbc/aesgcm с ключом в файле конфигурации: да, они шифруют etcd, но ключ шифрования лежит на узле control-plane открытым текстом, поэтому атакующий, способный прочитать данные etcd, обычно может прочитать и файл ключа. Это шаг вбок, а не фикс. Сильный выбор — KMS-провайдер, выполняющий envelope-шифрование: каждый секрет шифруется ключом данных (DEK), DEK шифруется ключом шифрования ключей (KEK), который живёт только внутри внешнего KMS (AWS KMS, GCP KMS, Vault), и API-сервер обязан сделать сетевой вызов к KMS для разворачивания. Теперь украденный снимок etcd — это инертный шифртекст. Учтите одну ловушку: включение шифрования шифрует только секреты, записанные после включения, — вы должны переписать каждый существующий секрет (kubectl get secrets -A -o json | kubectl replace -f -), чтобы реально запечатать то, что уже лежит.

Почему это работает

Почему нельзя просто включить шифрование на диске и считать дело сделанным? Потому что шифрование на диске защищает только один из пяти путей чтения из таблицы — путь украденного etcd. Оно ничего не делает против слишком широкого RBAC list, против kubectl exec в под со смонтированным секретом или против учётки, вставленной в лог CI. Шифрование на диске необходимо и его часто пропускают, но это единственный слой. Поверхность чтения — вот что вы реально управляете, и большинство реальных утечек секретов происходит через RBAC и человеческое копирование, а не через украденные диски.

Расползание секретов: настоящий операционный сбой

Даже при включённом шифровании на диске и плотном RBAC сбой, который реально кусает команды, — это расползание (sprawl): один и тот же секрет скопирован в десять неймспейсов, вшит в три Docker-образа, вставлен в два хранилища переменных CI и закоммичен один раз в Git «просто чтобы разблокировать деплой». Расползание — вот что превращает одну ротацию в недельные археологические раскопки, а одну утечку — в инцидент масштаба всего парка, потому что вы больше не можете ответить «где живёт эта учётка?».

Зрелый паттерн — единый источник истины вне кластера плюс синхронизация внутрь, а не копирование внутрь. Канонический секрет вы держите в выделенном хранилище (Vault, AWS Secrets Manager, GCP Secret Manager), а контроллер — External Secrets Operator (ESO) или Secrets Store CSI Driver — подтягивает его в кластер как нативный Secret по требованию. Манифесты ссылаются на ExternalSecret, указывающий на хранилище; сама учётка никогда не лежит в Git, никогда в образе, а ротация происходит в одном месте и распространяется. Секрет в кластере становится кэшем, а не базой-источником записи.

Ограничь чтение секрета одним объектом

1/3
Выбери лучший вариант

У вас один пароль БД, используемый сервисами в шести неймспейсах. Сегодня это вручную созданный Secret, скопированный в каждый. Выберите подход, который лучше всего предотвращает расползание и делает ротацию операцией в одном месте.

Викторина

Коллега говорит: «наши секреты в etcd в безопасности, потому что Kubernetes кодирует их в base64». Какая точная поправка?

Викторина

Вы включаете шифрование на диске с KMS-провайдером на кластере, где уже есть 200 секретов. Что ещё нужно сделать и почему?

Расставь шаги по порядку

Упорядочьте от самого слабого к самому сильному как способ защитить пароль БД в Kubernetes:

  1. 1 Base64-Secret, закоммиченный в Git (открытый текст в истории)
  2. 2 Обычный Secret в etcd, без шифрования на диске
  3. 3 Шифрование на диске с локальным ключом aescbc на узле
  4. 4 Шифрование на диске через внешний KMS (envelope-шифрование)
  5. 5 Внешнее хранилище + синхронизация ESO, плотный RBAC, без копий в Git/образах
Вспомните перед уходом
  1. 01
    Объясните, почему секрет Kubernetes не зашифрован, и перечислите, кто реально может его прочитать.
  2. 02
    Что такое расползание секретов, почему это реальный сбой и какой паттерн его предотвращает?
Итог

Секрет Kubernetes закодирован в base64, а это кодирование без ключа, а не шифрование — base64 -d обращает его мгновенно, поэтому секрет в комментарии Jira или закоммиченном манифесте — это утечка открытой учётки. По сравнению с ConfigMap секрет даёт операционные свойства (не печатается в открытых логах, монтирование tmpfs, отдельный RBAC), но никогда — конфиденциальность на диске. Его поверхность чтения широка: по умолчанию открытый текст в etcd, RBAC list (который возвращает содержимое), монтирование в под, авто-смонтированные токены ServiceAccount и CI/Git. Закрытие пути через etcd — это включение шифрования на диске, причём с выбором KMS-провайдера для настоящего envelope-шифрования, а не локального ключа aescbc, лежащего на том же узле, и с памятью о том, что нужно переписать существующие секреты, ведь шифрование применяется только при записи. Но сбой, который реально вызывает инциденты, — это расползание: копии одной учётки, разбросанные по неймспейсам, образам, CI и Git, делающие ротацию невозможной и превращающие одну утечку в компрометацию всего парка. Зрелый фикс — один внешний источник истины, синхронизируемый внутрь через External Secrets Operator или CSI-драйвер, — ссылка, а не копия, — чтобы секрет в кластере был кэшем, а ротация происходила ровно в одном месте. В следующий раз, увидев data:, полное base64, ваш рефлекс должен быть: кто может читать etcd, у кого есть list и сколько копий этого существует?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.