Files
aurum/docker-compose.yml
ZProger 14948aff1d security: TLS, проверка Host, шифрованное запоминание входа и аудит-лог
- TLS через подключаемый overlay docker-compose.tls.yml + Caddyfile:
  Caddy сам получает и продлевает сертификат Let's Encrypt, HSTS
  добавляется на уровне прокси — намеренно там, а не в nginx.conf,
  иначе установки без TLS заперли бы сами себя;
- проверка заголовка Host против DNS rebinding: AURUM_ALLOWED_HOSTS,
  по умолчанию localhost и 127.0.0.1, чужой Host получает 421 с
  подсказкой, какую переменную поправить;
- «запомнить меня на 7 дней» вернулось в безопасном виде: пароль
  шифруется AES-GCM ключом с extractable: false в IndexedDB, вместо
  прежнего base64 в localStorage, который разворачивался обратно в
  пароль одним atob. Требует secure context, поэтому по обычному HTTP
  к LAN-адресу чекбокс не показывается, а не притворяется рабочим;
- аудит-лог необратимых операций (восстановление бэкапа, массовое
  создание транзакций, удаление счёта) в лог контейнера. Не в БД
  сознательно: таблица аудита исчезла бы ровно в том событии, которое
  должна объяснять;
- README: раздел про TLS и таблица двух переменных, решающих, кто
  может достучаться до инстанса.
2026-09-10 21:34:40 +03:00

79 lines
3.4 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:-}
# Hostnames this instance answers to — anything else gets a 421.
# See frontend/docker-entrypoint.d/25-allowed-hosts.sh.
AURUM_ALLOWED_HOSTS: ${AURUM_ALLOWED_HOSTS:-localhost 127.0.0.1}
depends_on:
- backend
volumes:
aurum_pgdata: