Перейти к содержанию
Innovialabs

ConfigMap и Secret в Kubernetes: как управлять конфигурацией

Практика4 мин

Коротко

Обычные настройки храните в ConfigMap, пароли и токены — в Secret, передавайте их через переменные окружения или файлы и помните, что base64 — это кодирование, а не шифрование: защищайте секреты через RBAC, шифрование etcd и Sealed Secrets или External Secrets Operator.

Коротко

Kubernetes отделяет конфигурацию от образа контейнера двумя объектами:

  • ConfigMap — несекретные настройки: feature-флаги, адреса других сервисов, уровень логирования, конфиг-файлы.
  • Secret — чувствительные данные: пароли, API-токены, TLS-сертификаты.

Оба объекта попадают в под одним из двух способов: как переменные окружения или как файлы в смонтированном томе. Благодаря этому один и тот же образ работает в dev, staging и production с разной конфигурацией.

Главная оговорка: значения в Secret только закодированы в base64. Любой, кто может прочитать объект, расшифрует его одной командой. Реальная защита — это права доступа, шифрование при хранении и отсутствие открытых секретов в Git.

Как создать ConfigMap и Secret

Для быстрых проверок подойдут команды:

kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-file=app.yaml
kubectl create secret generic db-credentials --from-literal=DB_PASSWORD=change-me

В рабочих проектах лучше декларативные манифесты. Поле stringData в Secret позволяет писать значения как есть — Kubernetes сам закодирует их при сохранении:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  API_BASE_URL: "https://api.internal"
---
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
stringData:
  DB_PASSWORD: "change-me"

Такой манифест Secret нельзя коммитить в Git — об этом ниже.

Переменные окружения или файлы

containers:
  - name: app
    image: registry.example.com/app:1.4.0
    envFrom:
      - configMapRef:
          name: app-config
    env:
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: db-credentials
            key: DB_PASSWORD
    volumeMounts:
      - name: config
        mountPath: /etc/app
        readOnly: true
volumes:
  - name: config
    configMap:
      name: app-config
Переменные окруженияФайлы в томе
Для чегоПростые пары ключ-значениеЦелые конфиг-файлы, сертификаты
Обновляются при изменении объектаНет, только после перезапуска подаДа, с задержкой (кроме subPath)
РискМогут утечь в логи, дампы, дочерние процессыДоступны всему, что читает файлы в контейнере

Практичное правило: мелкие настройки — через env, файлы и сертификаты — через тома, а секреты по возможности передавайте файлами.

Как обновлять конфигурацию

Изменение ConfigMap ничего не перезапускает. Результат зависит от способа подключения:

  • Переменные окружения внутри работающего контейнера не меняются. Нужен новый rollout.
  • Файлы в томе kubelet со временем обновит, но приложение должно перечитать файл. Многие читают конфиг только при старте.

Рабочие подходы:

  1. Перезапустить деплоймент после изменения: kubectl rollout restart deployment/app.
  2. Добавить аннотацию с хешем конфига в шаблон пода (это удобно делать в Helm и Kustomize). Конфиг изменился — изменился хеш — поды пересоздаются автоматически.
  3. Использовать неизменяемые версионированные ConfigMap (app-config-v7, immutable: true) и переключать деплоймент на новое имя. Откат становится тривиальным.
  4. Следить за файлом в приложении, если изменения нужно подхватывать без перезапуска.

Почему base64 — не шифрование

Base64 лишь позволяет хранить бинарные данные как текст. Для декодирования ключ не нужен:

kubectl get secret db-credentials -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

Поэтому настоящая защита строится так:

  • RBAC: ограничьте get, list и watch для Secret. Учтите, что list тоже отдаёт значения.
  • Шифрование при хранении в etcd (настраивается на API-сервере или включается у managed-провайдера).
  • Никаких открытых Secret в Git и секретов, зашитых в образ.
  • Ограничьте, кто может создавать поды в namespace: любой, кто запускает там под, может смонтировать его секреты.

Как безопасно хранить секреты в Git

ИнструментКак работаетКому подходит
Sealed SecretsSecret шифруется публичным ключом кластера, расшифровать может только контроллер внутри негоGitOps-командам без внешнего хранилища
External Secrets OperatorСинхронизирует значения из внешнего хранилища (облачные secret managers, Vault) в SecretКомандам с централизованным хранилищем секретов
SOPSШифрует значения в файлах ключами KMS или age, расшифровка при деплоеПайплайнам на Helm или Kustomize

Частые ошибки

  • Положить пароль в ConfigMap «временно».
  • Закоммитить Secret в base64 и считать его скрытым.
  • Ждать, что env обновятся после правки ConfigMap.
  • Монтировать через subPath и удивляться, что файлы не обновляются.
  • Выдать CI или разработчикам права на чтение всех Secret в кластере.

Частые вопросы

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

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.