Files
aurum/docker-compose.yml
ZProger f9413aa6e1 security: устранить находки аудита, версия 1.1.7
Конфигурация и эксплуатационный слой:
- nginx: client_max_body_size 64m — восстановление из бэкапа не работало
  вовсе, дефолтный лимит в 1 МБ резал дампы (реальный экспорт ~3.4 МБ)
  с 413 ещё до backend;
- nginx: заголовки безопасности (nosniff, Referrer-Policy,
  Permissions-Policy) и полный Content-Security-Policy. Ради него
  inline-скрипт темы вынесен в public/theme-init.js;
- nginx: limit_req на /api/ — перебор пароля Basic Auth шёл со
  скоростью сети, ни блокировки, ни задержки не было;
- nginx: server_tokens off;
- порт web привязан к 127.0.0.1, адрес настраивается через
  AURUM_BIND_ADDRESS (раньше слушался на всех интерфейсах);
- backend работает от непривилегированного пользователя,
  no-new-privileges для backend и web;
- дефолты пароля Postgres сведены к одному значению в обоих сервисах,
  в .env.example описана ловушка с инициализацией тома.

Приложение:
- версия убрана из неавторизованного /api/health и отдаётся как
  app_version в GET /api/settings;
- /api/docs, /api/redoc и /api/openapi.json отключаются через
  AURUM_ENABLE_DOCS;
- текст исключения при неудачном восстановлении уходит в лог, а не
  клиенту;
- max_length для notes в схемах транзакций, активов и регулярных
  платежей (и в соответствующих полях UI);
- срок «запомнить меня» сокращён с 30 дней до 7;
- pytest обновлён до 9.0.3 (PYSEC-2026-1845), pytest-asyncio до 1.4.0;
- CI: permissions contents:read для GITHUB_TOKEN.
2026-09-10 21:12:31 +03:00

76 lines
3.2 KiB
YAML

services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${AURUM_POSTGRES_USER:-aurum}
# "change-me" so this matches .env.example exactly: with no .env at all
# the fallback here used to be "aurum" while the template said
# "change-me", i.e. "the default password" meant two different things
# depending on whether the file existed. Postgres isn't published to the
# host (no ports: below), so reaching it means already being on the
# container network — but see .env.example for the trap that makes this
# worth getting right the first time.
POSTGRES_PASSWORD: ${AURUM_POSTGRES_PASSWORD:-change-me}
POSTGRES_DB: ${AURUM_POSTGRES_DB:-aurum}
volumes:
- aurum_pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${AURUM_POSTGRES_USER:-aurum}"]
interval: 5s
timeout: 5s
retries: 10
backend:
build: ./backend
restart: unless-stopped
# Nothing here ever needs to gain privileges (no setuid binaries, no sudo),
# so forbid it outright — this is what stops a compromised process from
# escalating back to root inside the container.
security_opt:
- no-new-privileges:true
environment:
AURUM_POSTGRES_USER: ${AURUM_POSTGRES_USER:-aurum}
# Must stay identical to the db service's fallback above — if the two
# drift, an install without .env brings up a database with one password
# and a backend dialling it with another.
AURUM_POSTGRES_PASSWORD: ${AURUM_POSTGRES_PASSWORD:-change-me}
AURUM_POSTGRES_DB: ${AURUM_POSTGRES_DB:-aurum}
AURUM_POSTGRES_HOST: db
AURUM_POSTGRES_PORT: 5432
AURUM_CORS_ORIGINS: ${AURUM_CORS_ORIGINS:-}
AURUM_DEFAULT_CURRENCY: ${AURUM_DEFAULT_CURRENCY:-USD}
# Free CoinGecko Demo key (coingecko.com/en/api/pricing) — the Crypto
# tab's price sync 400s with a clear message until this is set.
AURUM_COINGECKO_API_KEY: ${AURUM_COINGECKO_API_KEY:-}
AURUM_ENABLE_DOCS: ${AURUM_ENABLE_DOCS:-true}
depends_on:
db:
condition: service_healthy
web:
build: ./frontend
restart: unless-stopped
# nginx's master still needs root to bind :80 and to write the htpasswd
# file at boot (docker-entrypoint.d/20-basic-auth.sh), so this one can't
# drop to a non-root user without reworking both — but it can still be
# barred from escalating any further.
security_opt:
- no-new-privileges:true
ports:
# Bound to loopback by default: published as "3000:80" the app answers
# on every interface, so anyone on the same Wi-Fi reaches it — and by
# default there is no password on it at all (see 20-basic-auth.sh).
# Set AURUM_BIND_ADDRESS=0.0.0.0 to reach it from other devices, but
# set AURUM_BASIC_AUTH_USER/PASSWORD before you do.
- "${AURUM_BIND_ADDRESS:-127.0.0.1}:${AURUM_WEB_PORT:-3000}:80"
environment:
# Both unset = no login screen at all. See frontend/docker-entrypoint.d/20-basic-auth.sh.
AURUM_BASIC_AUTH_USER: ${AURUM_BASIC_AUTH_USER:-}
AURUM_BASIC_AUTH_PASSWORD: ${AURUM_BASIC_AUTH_PASSWORD:-}
depends_on:
- backend
volumes:
aurum_pgdata: