Перейти к содержимому

23. Секреты и конфиденциальные данные

Управление секретами — один из наиболее критических аспектов безопасности контейнеризованных приложений. Секреты (пароли, токены, ключи) никогда не должны попадать в Dockerfile или образ.

# ❌ НИКОГДА ТАК НЕ ДЕЛАЙТЕ
FROM node:20-alpine
ENV DB_PASSWORD=supersecret123
ENV JWT_SECRET=my_jwt_secret
COPY .env . # секреты попадают в образ!
# Даже если удалить в следующем слое — они ОСТАЮТСЯ в истории образа!
RUN rm .env # бесполезно — данные уже в предыдущем слое

Почему это опасно:

  • Секреты записаны в слои образа навсегда
  • docker history myapp покажет ENV-переменные
  • Если образ попадёт в публичный реестр — секреты утекут
Окно терминала
# Создать секрет из строки
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
const fs = require('fs');
// Читать из Docker Secrets
function 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');
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 secrets
# syntax=docker/dockerfile:1
FROM node:20-alpine AS builder
WORKDIR /app
COPY 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 Vault
vault kv put secret/myapp db_password=secret jwt_secret=token
# AWS Secrets Manager
aws secretsmanager create-secret \
--name myapp/db_password \
--secret-string "mysupersecret"
# Kubernetes Secrets
kubectl create secret generic myapp-secrets \
--from-literal=db_password=secret \
--from-literal=jwt_secret=token