← Kubernetes: Kustomize и Helm
5 мин · просто · Урок 6 из 9

Kustomize: генератор Secret

secretGenerator и честный разбор того, что base64 в Secret ничего не защищает.

Secret - это объект Kubernetes для чувствительных данных: паролей, токенов, ключей и сертификатов. Устроен он почти как ConfigMap, отличается типом объекта, отдельными правилами доступа и тем, что значения хранятся в поле data закодированными в base64.

secretGenerator работает по тем же правилам, что и configMapGenerator. Те же три источника, тот же хеш-суффикс, тот же блок generatorOptions.

Генерация из literals

secretGenerator:
  - name: app-secret
    literals:
      - DB_PASSWORD=s3cr3t
      - API_TOKEN=abc123

Значения пишутся как есть. Кодировать в base64 руками не нужно: Kustomize сделает это при рендере. На выходе получится Secret типа Opaque с полем data, где значения уже закодированы.

Секрет из файлов

Для сертификатов и ключей удобнее files, потому что PEM-файл в literals не вставишь:

secretGenerator:
  - name: web-tls
    type: kubernetes.io/tls
    files:
      - tls.crt=certs/site.pem
      - tls.key=certs/site.key

Поле type задаёт тип Secret. Для kubernetes.io/tls Kubernetes требует ровно ключи tls.crt и tls.key, поэтому исходные файлы переименовываются при подключении. Без указания type получится обычный Opaque.

Есть ещё envs, который разбирает файл КЛЮЧ=значение построчно. Полезно, когда набор переменных уже лежит в .env-файле.

Файл попадает в Secret ровно как есть, вместе с завершающим переводом строки. Пароль, сгенерированный через echo, приедет на символ длиннее и не подойдёт. Спасает echo -n или printf.

base64 - это кодирование, а не шифрование

Значения в Secret выглядят как случайный текст, и это легко принять за защиту. Защиты там нет. base64 - обратимое кодирование, придуманное для передачи бинарных данных текстом. Любой, у кого есть право читать Secret, достанет исходное значение одной командой:

kubectl get secret app-secret-9t2hk4m6c2 -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

Что действительно ограничивает доступ:

Практическая ценность Secret в том, что он отделяет чувствительные данные от остальной конфигурации и даёт для них отдельную точку контроля доступа. Само содержимое объект не шифрует.

По этой же причине kubectl kustomize . печатает готовый Secret в терминал. В CI такой вывод уезжает в логи пайплайна, где его прочитает любой, у кого есть доступ к сборкам.

Хеш-суффикс

Как и у ConfigMap, к имени добавляется хеш содержимого: app-secret-9t2hk4m6c2. Меняется значение - меняется имя, Kustomize правит ссылку в Deployment, кластер запускает rollout, и Pod подхватывают новый пароль. Отключается тем же способом:

generatorOptions:
  disableNameSuffixHash: true

Что обычно ломается

Пароль в literals попадает в git открытым текстом. Это главная проблема secretGenerator, и решают её не Kustomize. В репозитории держат либо зашифрованные файлы (SOPS, sealed-secrets), либо только ссылку на внешнее хранилище, а literals оставляют для локальных экспериментов.

Рендер для отладки лучше не делать на шаге, который пишет логи в общий доступ.

Смена типа Secret на живом объекте не проходит: поле type неизменяемое. Если Secret создавали как Opaque, а потом решили сделать kubernetes.io/tls, объект придётся удалить и создать заново.

Домашка

Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-kustomize-secret-generator     # развернуть стартовое состояние
./run.sh verify k8s-kustomize-secret-generator    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.