Автогенерация секретов в Helm

Автогенерация секретов в Helm

Команда Kubernetes aaS от Mail.ru перевела короткую заметку о том, как автоматически генерировать секреты Helm при обновлении. Далее текст от автора статьи — технического директора Intoware, компании-разработчика SaaS-решений.

Контейнеры — это круто. Сначала я был противником контейнеров (стыдно признаться), но теперь я полностью поддерживаю использование этой технологии. Если вы читаете это, то, надеюсь, успешно плавали по морям Docker, осознали преимущества Kubernetes и сделали свою жизнь намного проще с Helm.

Тем не менее некоторые вещи явно сложнее, чем должны быть.

Как автоматически генерировать секреты при обновлении?

Секрет Kubernetes — ресурс, который содержит пары ключ/значение, которые вы хотите использовать в своем коде. Это могут быть строки подключения к базе данных, пароли электронной почты и так далее. Используя секреты, вы создаете четкое разделение между кодом и настройками, что позволяет легко настраивать различные развертывания без изменения кодовой базы.

Часто встречающаяся ситуация, когда два модуля должны взаимодействовать при помощи общего ключа. Никто за пределами кластера не должен знать этот ключ, так как он предназначен для связи «от одного к другому» внутри кластера.

Создание секретов

Обычно, чтобы создать секрет в Helm, нужно:

  • описать секрет в файле значений;
  • переопределить его в процессе деплоя;
  • сослаться на него внутри деплоя/пода;
  • … профит !

Обычно это выглядит примерно так:

apiVersion: v1
kind: Secret
metadata:
  name: my-super-awesome-api-key
type: Opaque
stringData:
  apiKey: {{ .Values.MyApiKeySecret | quote }}

Простой секрет Kubernetes, использующий значения из values.yml

Но, допустим, вы не хотите указывать свой секрет в файле значений.

Существует много вариантов, когда для развертывания требуется общий ключ, который должен быть сгенерирован во время установки.

В приведенном выше примере со связью между модулями нежелательно делиться секретом за пределами развертывания. Поэтому очень желательно, чтобы Helm имел механизмы для автоматического создания секрета без необходимости его непосредственного указания.

Хуки

Хуки позволяют запускать код в определенных местах в процессе установки. Возможно, есть задание по настройке, которое необходимо запустить после первой установки, или, возможно, необходимо выполнить очистку перед выполнением любого обновления.

Для решения нашей проблемы добавления ключа, генерируемого при установке, идеально подходят предустановочные хуки. Но есть одна загвоздка: вы не можете автоматически сгенерировать секрет один раз при обновлении. Хуки будут работать при каждом обновлении.

Если вы сгенерировали свой секрет, и ваша первая установка еще не произошла, тогда прекратите чтение, предустановочный хук отлично подойдет для вас.

Но если секрет является частью обновления (возможно, новой функции, которой не было во время установки), то досадно, что невозможно создать предустановочный хук, который бы сработал всего один раз.

Функции

Функции Helm позволяют добавлять различные элементы скриптов в сценарии развертывания.

apiVersion: v1
kind: Secret
metadata:
  name: my-super-awesome-api-key
type: Opaque
stringData:
  apiKey: {{ uuidv4 | quote }} #Generate a new UUID and quote it

В этом примере показано, что значением секрета apiKey будет новый UUID, сгенерированный во время установки.

Helm включает в себя действительно обширную библиотеку функций, которая использует потрясающие функции шаблонов GO и библиотеку функций Sprig для создания настраиваемых развертываний.

Функция Lookup

В Helm 3.1 добавлена функция Lookup, которая позволяет запросить существующий деплой и:

  • проверить существование ресурсов;
  • вернуть значение существующего ресурса для последующего использования.

Используя обе эти возможности, мы можем создать одноразовый динамически сгенерированный секрет!

# 1. Запросить существование секрета и вернуть в переменной $secret
{{- $secret := (lookup "v1" "Secret" .Release.Namespace "some-awesome-secret" -}}
apiVersion: v1
kind: Secret
metadata:
  name: some-awesome-secret
type: Opaque

# 2. Если секрет существует, взять его значение как apiKey (секрет использует кодирование Base64, так что используйте ключ "data")
{{ if $secret -}}
data:
  apiKey: {{ $secret.data.apiKey }}

# 3. Если секрет не существует — создать его (в этот раз используйте "stringData", так как будет обычное значение)!
{{ else -}}
stringData:
  apiKey: {{ uuidv4 | quote }}
{{ end }}

Всякий раз, когда новое обновление применяется к серверу, Helm будет либо генерировать новое значение секрета (если секрета еще нет), либо повторно использовать существующее значение.

Успехов!

Что еще почитать по теме:

  1. Три уровня автомасштабирования в Kubernetes и как их эффективно использовать.
  2. Kubernetes в духе пиратства с шаблоном по внедрению.
  3. Наш канал Вокруг Kubernetes в Телеграме.

Источник: habr.com