23. Секреты и конфиденциальные данные
Управление секретами — один из наиболее критических аспектов безопасности контейнеризованных приложений. Секреты (пароли, токены, ключи) никогда не должны попадать в Dockerfile или образ.
Проблема: секреты в образе
Заголовок раздела «Проблема: секреты в образе»# ❌ НИКОГДА ТАК НЕ ДЕЛАЙТЕFROM node:20-alpineENV DB_PASSWORD=supersecret123ENV JWT_SECRET=my_jwt_secretCOPY .env . # секреты попадают в образ!
# Даже если удалить в следующем слое — они ОСТАЮТСЯ в истории образа!RUN rm .env # бесполезно — данные уже в предыдущем слоеПочему это опасно:
- Секреты записаны в слои образа навсегда
docker history myappпокажет ENV-переменные- Если образ попадёт в публичный реестр — секреты утекут
Docker Secrets в Swarm
Заголовок раздела «Docker Secrets в Swarm»# Создать секрет из строкиecho "mysupersecretpassword" | docker secret create db_password -
# Создать секрет из файлаdocker secret create ssl_cert ./ssl.crt
# Список секретовdocker secret ls
# Детали секрета (содержимое недоступно!)docker secret inspect db_password
# Использовать в сервисеdocker service create \ --name myapi \ --secret db_password \ --secret ssl_cert \ myapp
# В контейнере секрет доступен как файл:# /run/secrets/db_password# /run/secrets/ssl_certЧтение секретов в Node.js
Заголовок раздела «Чтение секретов в Node.js»const fs = require('fs');
// Читать из Docker Secretsfunction getSecret(secretName) { const secretPath = `/run/secrets/${secretName}`; const envVar = process.env[secretName.toUpperCase()];
if (fs.existsSync(secretPath)) { return fs.readFileSync(secretPath, 'utf8').trim(); } if (envVar) { return envVar; } throw new Error(`Secret ${secretName} not found`);}
const dbPassword = getSecret('db_password');const jwtSecret = getSecret('jwt_secret');Docker Compose Secrets
Заголовок раздела «Docker Compose Secrets»version: '3.8'services: api: image: myapi secrets: - db_password - jwt_secret environment: - DATABASE_URL=postgresql://user@postgres/mydb
postgres: image: postgres:15 secrets: - db_password environment: POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets: db_password: file: ./secrets/db_password.txt # из файла jwt_secret: external: true # из Docker Swarm secretsBuildKit Secrets: секреты при сборке
Заголовок раздела «BuildKit Secrets: секреты при сборке»# syntax=docker/dockerfile:1
FROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./
# Секрет используется ТОЛЬКО во время сборки, не попадает в образRUN --mount=type=secret,id=npm_token \ export NPM_TOKEN=$(cat /run/secrets/npm_token) && \ npm ci
COPY . .RUN npm run build# Сборка с BuildKit секретомdocker build \ --secret id=npm_token,src=.npmrc_token \ -t myapp .Внешние системы управления секретами
Заголовок раздела «Внешние системы управления секретами»# HashiCorp Vaultvault kv put secret/myapp db_password=secret jwt_secret=token
# AWS Secrets Manageraws secretsmanager create-secret \ --name myapp/db_password \ --secret-string "mysupersecret"
# Kubernetes Secretskubectl create secret generic myapp-secrets \ --from-literal=db_password=secret \ --from-literal=jwt_secret=token