Gymterview
middle

Как правильно управлять секретами в контейнерах?

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

Как НЕ надо хранить секреты

Пример
# НЕПРАВИЛЬНО: секрет в Dockerfile -- сохраняется во ВСЕХ слоях образа!
ENV DB_PASSWORD=SuperSecret123
RUN echo "password=SuperSecret123" > /app/config.properties

# НЕПРАВИЛЬНО: использование ARG -- видно через docker history
ARG DB_PASSWORD
RUN echo $DB_PASSWORD > /app/config.properties
Пример
# НЕПРАВИЛЬНО: секрет в docker run через переменную окружения
docker run -e DB_PASSWORD=SuperSecret123 my-app

# Секрет виден через:
docker inspect <container_id>  # в разделе Env
cat /proc/1/environ            # внутри контейнера
Пример
# НЕПРАВИЛЬНО: секрет в plain-text в Kubernetes манифесте (попадёт в Git!)
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    env:
    - name: DB_PASSWORD
      value: "SuperSecret123"

Kubernetes Secrets (базовый уровень)

Kubernetes Secrets кодирует данные в base64 – это не шифрование, а лишь кодирование. Для реальной защиты необходимо включить encryption at rest.

Пример создания и использования Kubernetes Secret
# Создание секрета
apiVersion: v1
kind: Secret
metadata:
  name: banking-db-credentials
  namespace: banking
type: Opaque
data:
  username: YWRtaW4=          # base64 (НЕ шифрование!)
  password: UGFzc3dvcmQxMjM=  # base64

---
# Использование секрета как volume (рекомендуемый способ)
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    image: registry.bank.local/banking-service:1.0.0
    volumeMounts:
    - name: db-creds
      mountPath: /etc/secrets/db
      readOnly: true
  volumes:
  - name: db-creds
    secret:
      secretName: banking-db-credentials
      defaultMode: 0400  # Только чтение для владельца

Чтение секрета в Spring Boot:

Пример
@Value("file:/etc/secrets/db/password")
private String dbPassword;
Настройка encryption at rest для секретов в etcd
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64-encoded-32-byte-key>
  - identity: {}

HashiCorp Vault (enterprise-уровень)

Vault – рекомендуемое решение для банковских систем. Vault Agent Injector автоматически подставляет секреты в файлы внутри пода.

Пример интеграции Vault с Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: banking-service
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "banking-service"
        vault.hashicorp.com/agent-inject-secret-db-password: "secret/data/banking/db"
        vault.hashicorp.com/agent-inject-template-db-password: |
          {{- with secret "secret/data/banking/db" -}}
          {{ .Data.data.password }}
          {{- end -}}
    spec:
      serviceAccountName: banking-service
      containers:
      - name: app
        image: registry.bank.local/banking-service:1.0.0

Vault Agent автоматически подставит секрет в файл /vault/secrets/db-password внутри пода.

Docker Secrets (для Docker Swarm)

Пример
# Создание секрета
echo "SuperSecret123" | docker secret create db_password -
Пример
version: '3.8'
services:
  banking-service:
    image: banking-service:1.0.0
    secrets:
      - db_password
secrets:
  db_password:
    external: true

Секрет доступен внутри контейнера по пути /run/secrets/db_password в tmpfs (не записывается на диск).

Sealed Secrets (Bitnami) – для хранения секретов в Git

Пример
# Зашифровать секрет публичным ключом кластера
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
Пример
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: banking-db-credentials
spec:
  encryptedData:
    password: AgBy3i...encrypted...data...==

Sealed Secret можно безопасно хранить в Git – расшифровать его может только контроллер в кластере.

External Secrets Operator – интеграция с внешними хранилищами

Пример ExternalSecret для интеграции с Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: banking-db-creds
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: banking-db-credentials
  data:
  - secretKey: password
    remoteRef:
      key: secret/data/banking/db
      property: password

Сравнение подходов

Подход Шифрование Ротация GitOps-совместимость Рекомендация
Kubernetes Secrets base64 (нет) Ручная Нет (plain-text) Минимум + encryption at rest
Sealed Secrets RSA Ручная Да Для небольших команд
HashiCorp Vault AES-256 Автоматическая Через ESO Для банков и enterprise
External Secrets Operator Зависит от бэкенда Автоматическая Да Универсальный выбор

Вывод

Секреты никогда не должны попадать в образ, исходный код или переменные окружения в открытом виде. Для банковских систем рекомендуется HashiCorp Vault с Vault Agent Injector или External Secrets Operator. Минимальное требование – Kubernetes Secrets с encryption at rest и монтированием через volume (не через env).

На собеседовании: начните с антипаттернов (секрет в ENV, в Dockerfile, в plain-text манифесте), затем покажите правильные подходы. Обязательно подчеркните, что base64 – это не шифрование. Упомяните Vault и Sealed Secrets для полноты.