Раскрою вам тайну: если положить пароль в Secret, он там не будет в безопасности💀
Напрашивается вопрос, а почему он НЕ в безопасности? Всё просто, Secret в Kubernetes по умолчанию не зашифрован. Он закодирован в base64, что является кодировкой, а не шифрованием. Любой, у кого есть доступ к кластеру, декодирует его одной командой. Но давайте по порядку
Для начала разберемся, что такое ConfigMap
ConfigMap - объект API Kubernetes для хранения неконфиденциальных данных в формате ключ-значение. Типичное содержимое:
• Конфигурационные файлы приложений (nginx.conf, application.properties)
• Переменные окружения (LOG_LEVEL, DB_HOST)
• Флаги и настройки, которые отличаются между окружениями (dev/staging/prod)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "debug"
DATABASE_HOST: "postgres.default.svc.cluster.local"
app.conf: |
server {
listen 80;
server_name localhost;
}
А Secret, в свою очередь, - тот же ConfigMap, но предназначенный для конфиденциальных данных: пароли, токены, TLS-сертификаты, SSH-ключи
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # echo -n "admin" | base64
password: cGFzc3dvcmQ= # echo -n "password" | base64
Главная "иллюзия безопасности": значение в поле data - это base64, а не шифрование, а обратимая кодировка, которую можно декодировать без ключа
echo "cGFzc3dvcmQ=" | base64 -d
# Вывод: password
Как всё-таки можно реально защитить Secret
• Encryption at Rest. Включить шифрование etcd через EncryptionConfiguration. Тогда данные шифруются на диске, но в памяти API-server всё ещё расшифрованы
• RBAC. Ограничить доступ к Secrets через Role и RoleBinding. Не давать get/list на Secrets всем namespace'ам
• External Secrets. Хранить секреты во внешнем хранилище (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault) и синхронизировать их в кластер через оператор (External Secrets Operator)
• Sealed Secrets (Bitnami). Шифровать Secrets на стороне разработчика публичным ключом. В кластере расшифровывает только контроллер с приватным ключом. Безопасно хранить в Git
Ещё важно разобраться, как передавать ConfigMap/Secret в под
Способ 1: Переменные окружения (env)
containers:
- name: app
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
Здесь значение подставляется при старте контейнера. Если обновить Secret/ConfigMap, то контейнер не увидит изменения до перезапуска. Способ подходит для значений, которые не меняются в runtime
Способ 2: Volume mount
volumes:
- name: config-volume
configMap:
name: app-config
containers:
- name: app
volumeMounts:
- name: config-volume
mountPath: /etc/config
ConfigMap/Secret монтируется как файл в файловую систему контейнера. При обновлении ConfigMap/Secret файл обновляется автоматически (kubelet периодически синхронизирует, задержка до 60–120 секунд). Способ подходит для конфигурационных файлов, которые приложение умеет перечитывать сходу

