Как вы храните секретные переменные (например, пароли, API-ключи) в DevOps-практиках?

«Как вы храните секретные переменные (например, пароли, API-ключи) в DevOps-практиках?» — вопрос из категории Безопасность, который задают на 24% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В DevOps мы используем специализированные инструменты для управления секретами, чтобы избежать их попадания в код репозитория. Основные подходы:

1. Специализированные сервисы (Secrets as a Service):

  • HashiCorp Vault: Наиболее гибкое решение с динамическими секретами, шифрованием и детальным аудитом.
  • Cloud-native менеджеры: AWS Secrets Manager, Azure Key Vault, GCP Secret Manager. Плотно интегрированы с экосистемой своего облака.

2. Интеграция с оркестраторами:

  • Kubernetes Secrets: Базовый, но небезопасный по умолчанию (base64 — не шифрование). Всегда использую вместе с:
    • SealedSecrets (шифрование на стороне клиента).
    • External Secrets Operator (синхронизация из внешних хранилищ, например, Vault).
    • Зашифрованный etcd (с помощью провайдеров, например, от AWS, GCP или с использованием kms).

3. Интеграция в CI/CD:

  • Переменные окружения, помеченные как protected/masked в GitLab CI/CD, GitHub Actions, Jenkins Credentials.

Пример создания и использования секрета в Kubernetes через kubectl:

# Создание секрета из литералов
kubectl create secret generic app-db-cred 
  --from-literal=username=prod_user 
  --from-literal=password='S3cr3tP@ss!'

# Создание секрета из файла
kubectl create secret generic tls-cert --from-file=./tls.crt

Пример манифеста для монтирования секрета как переменных окружения в Pod:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
      - name: DB_USERNAME
        valueFrom:
          secretKeyRef:
            name: app-db-cred
            key: username
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: app-db-cred
            key: password
    volumeMounts:
    - name: cert-volume
      mountPath: /etc/ssl/certs
  volumes:
  - name: cert-volume
    secret:
      secretName: tls-cert

Лучшие практики, которых я придерживаюсь:

  • Никогда не коммитить секреты в Git (даже в .env файлах, которые добавлены в .gitignore — это лишь полумера для локальной разработки).
  • Принцип наименьших привилегий: Сервисы и пользователи получают доступ только к необходимым им секретам.
  • Ротация: Автоматическая смена ключей и паролей по расписанию или событию.
  • Аудит: Все операции чтения/записи секретов должны логироваться.