ConfigMap и Secret отделяют конфигурацию от образа контейнера и позволяют менять её без пересборки. Разные окружения используют разные значения с одним и тем же образом.
[source: kubernetes.io/docs/concepts/configuration/configmap/]
ConfigMap
ConfigMap хранит неконфиденциальные конфигурационные данные в виде пар ключ-значение. Размер — до 1 MiB.
Создание ConfigMap
Из литералов:
kubectl create configmap app-config \
--from-literal=DB_HOST=postgres \
--from-literal=DB_PORT=5432 \
--from-literal=LOG_LEVEL=info
Из файла:
# Файл целиком как одно значение (ключ = имя файла)
kubectl create configmap nginx-config --from-file=nginx.conf
# С явным ключом
kubectl create configmap nginx-config --from-file=my-nginx=nginx.conf
# Из .env файла (каждая строка KEY=VALUE становится отдельным ключом)
kubectl create configmap app-config --from-env-file=.env
Через YAML-манифест (рекомендуется для GitOps):
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
DB_HOST: postgres
DB_PORT: "5432"
LOG_LEVEL: info
app.properties: |
server.port=8080
server.context-path=/api
feature.cache.enabled=true
Использование ConfigMap
Все ключи как переменные окружения (envFrom):
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
Все ключи ConfigMap становятся переменными окружения контейнера.
Отдельные ключи (valueFrom):
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
Как файлы через Volume (рекомендуется для конфигов с автообновлением):
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
Каждый ключ ConfigMap становится файлом в /etc/config/. При обновлении ConfigMap файлы в Volume обновляются автоматически (с задержкой до kubelet sync period — обычно ~1 минута). Переменные окружения (env/envFrom) не обновляются — требуется перезапуск Pod.
Secret
Secret хранит конфиденциальные данные: пароли, токены, ключи. По структуре аналогичен ConfigMap, но значения хранятся в base64. Размер — до 1 MiB.
[source: kubernetes.io/docs/concepts/configuration/secret/]
Создание Secret
Императивно:
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=s3cret123
Через YAML с data (значения в base64):
# Кодирование
echo -n 'admin' | base64 # YWRtaW4=
echo -n 's3cret123' | base64 # czNjcmV0MTIz
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4=
password: czNjcmV0MTIz
Через YAML с stringData (без ручного кодирования):
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: admin
password: s3cret123
stringData автоматически кодируется в base64 при сохранении. Удобнее для манифестов, но не коммить такие файлы в git без шифрования (Sealed Secrets, SOPS).
Типы Secret
# TLS Secret
kubectl create secret tls my-tls \
--cert=server.crt \
--key=server.key
# Docker registry Secret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass
Использование Secret
Как переменные окружения:
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
Как файлы через Volume (предпочтительно):
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
Volume mount предпочтительнее env для Secret: файлы обновляются автоматически при ротации, не попадают в kubectl describe pod вывод так легко, не логируются средами выполнения.
Docker registry credentials (imagePullSecrets):
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.example.com/myapp:1.0
Безопасность Secret
Secret хранятся в etcd в base64 — это кодирование, не шифрование. Декодируется тривиально:
echo 'czNjcmV0MTIz' | base64 -d # s3cret123
Encryption at rest
Для шифрования Secret в etcd настраивается EncryptionConfiguration на API Server:
[source: kubernetes.io/docs/tasks/administer-cluster/encrypt-data/]
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
Рекомендации
- Не коммить Secret-манифесты в git в открытом виде
- Использовать Sealed Secrets (Bitnami) или SOPS для шифрования манифестов в репозитории
- Использовать внешние менеджеры секретов: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault — с CSI driver или оператором
- Включить encryption at rest в etcd
- Ограничить доступ к Secret через RBAC
- Монтировать как Volume вместо env
Сравнение ConfigMap и Secret
Типичные ошибки
Секрет в ConfigMap. Пароль или токен в ConfigMap — ошибка. ConfigMap не имеет дополнительных защитных механизмов.
Коммит Secret манифеста в git. stringData в YAML читается как plain text. Стандартное решение — Sealed Secrets или внешний secret manager.
Обновление ConfigMap не приводит к обновлению env в Pod. После обновления ConfigMap Pod с envFrom продолжает видеть старые значения до перезапуска. Для автоматического перезапуска при изменении ConfigMap используй Reloader (stakater/Reloader) или пересоздавай Pod через kubectl rollout restart.
Забыть readOnly: true при монтировании Secret. Хорошая практика — монтировать Secret как read-only.
Secret слишком большой. Лимит 1 MiB. Большие артефакты (TLS chain, binary keys) — в отдельные Secret или внешнее хранилище.
Альтернативы
HashiCorp Vault с Vault Agent Injector или CSI Secrets Store Driver — динамические секреты, аудит доступа, автоматическая ротация. Стандарт для security-требовательных окружений.
AWS Secrets Manager / Azure Key Vault / GCP Secret Manager — облачные менеджеры секретов с интеграцией через CSI Secrets Store Driver или нативные операторы.
Sealed Secrets (Bitnami) — шифрует Secret в SealedSecret ресурс, который безопасно хранить в git. Расшифровывается только контроллером в кластере.
SOPS — шифрует YAML/JSON файлы (включая Secret манифесты) с использованием KMS, PGP или age. Хорошо интегрируется с GitOps.