← Kubernetes: конфигурация
6 мин · средне · Урок 4 из 8

Immutable Secret: запрет на изменение данных

Что делает флаг immutable у Secret и ConfigMap, зачем он нужен и как ротировать данные, когда правки запрещены.

Зачем immutable

У Secret и ConfigMap с Kubernetes 1.21 (GA) есть поле immutable: bool. Если выставить true, API server запрещает менять data, stringData и binaryData. Можно только удалить и пересоздать.

Зачем это нужно:

  1. Защита от случайных правок. Конфиг или ключ не «уплывёт» через kubectl edit secret prod.
  2. Снижение нагрузки на kube-apiserver и kubelet. За каждым mutable secret/configmap kubelet держит watch и периодически синхронизирует данные в смонтированных volume. Для immutable watch не нужен: kubelet кеширует данные один раз. На кластере с тысячами Pod это заметная экономия запросов к API.
  3. Иммутабельные деплои. В CI генерируется уникальное имя (app-config-abc123), деплой ссылается на него, после ротации создаётся новый app-config-def456. Старый удаляется только когда на него никто не ссылается.

Манифест

apiVersion: v1
kind: Secret
metadata:
  name: db-password
type: Opaque
immutable: true
data:
  password: c2VjcmV0MTIz

data всегда в base64. stringData пишется в открытом виде, API server сам кодирует при сохранении (но в API всё равно лежит в data).

После kubectl apply Secret оказывается в API server. Поле immutable можно выставить позже на обычном Secret, но обратно снять нельзя (true → false запрещено). Чтобы поменять данные, Secret пересоздают.

Что запрещено

kubectl edit secret db-password
# Error from server (Forbidden): Forbidden: field is immutable when `immutable`
# is set
kubectl patch secret db-password \
  --type=merge -p '{"stringData":{"password":"new"}}'
# Error from server (Forbidden): Secret "db-password" is invalid:
# data: Forbidden: field is immutable when `immutable` is set
kubectl apply -f db-password.yaml  # с другим password
# Error from server (Invalid): ... field is immutable

Запрещено: изменение data, stringData, binaryData, переключение immutable: true → false.

Разрешено: правка metadata.labels и metadata.annotations. Также можно полностью удалить и создать заново - это два отдельных action.

Sealed Secrets или External Secrets пытается обновить Secret сам и упирается в тот же Forbidden. Либо выключают immutable, либо ротируют через новое имя.

Как «обновлять» immutable Secret

1. новый Secret db-password-v2 2. правка ссылки secretRef.name: v2 3. rollout новые Pod читают v2 4. delete v1 ссылок больше нет время
Данные не правятся на месте. Меняется имя, за ним ссылка, за ней Pod.

Главный паттерн - ротация через новое имя.

# Старый Secret остаётся нетронутым
apiVersion: v1
kind: Secret
metadata:
  name: db-password-v2  # новое имя
immutable: true
type: Opaque
data:
  password: bmV3LXNlY3JldA==

В Deployment правится ссылка:

envFrom:
  - secretRef:
      name: db-password-v2  # было v1

Rollout катит новые Pod с обновлённым ключом, старый Secret можно удалить, когда ни одна реплика на него не смотрит.

Альтернатива (грубее, но работает) - kubectl delete secret и сразу kubectl create secret. Уже запущенные Pod с этим Secret в volume продолжат работать на старых данных, новые значения подхватят только после пересоздания. Поэтому чище ротировать через envFrom и новый rollout.

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

Домашка

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

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

Коротко

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