docker-compose.hardened.yml
Rama main · réplica de lectura del repositorio original.
# Hardening overlay — apply on top of docker-compose.yml OR docker-compose.ghcr.yml:
#
# docker compose -f docker-compose.yml -f docker-compose.hardened.yml up -d
# docker compose -f docker-compose.ghcr.yml -f docker-compose.hardened.yml up -d
#
# Works with both rootful and rootless engines (Docker rootless / Podman). It
# adds no-new-privileges, capability dropping, a read-only app rootfs and
# resource limits. The app is a static binary that already runs as a non-root
# user and writes nothing to its container filesystem, so it can be locked down
# hard; Postgres needs a writable data dir and a few capabilities for its
# entrypoint, so it is hardened more conservatively.
services:
app:
# Static binary, logs to stdout, photos live in the DB — nothing is written
# to the container filesystem, so the rootfs can be read-only.
#
# Backup temp files (S3 upload and read-back, downloads, the decrypted dump
# during a restore) are as large as the database. They go to
# <PARKRR_BACKUP_DIR>/.tmp on the /backups volume, NOT to /tmp: keep
# PARKRR_BACKUP_DIR set to a writable volume, even for an S3-only setup (an
# empty volume cron keeps volume backups off). Plan free space there of about
# twice the archive size (S3 upload plus its read-back copy, or a staged
# upload plus the decrypted dump during a restore). Only with an empty
# PARKRR_BACKUP_DIR does the app fall back to /tmp, and the 32 MiB tmpfs below
# is far too small for that.
# Tax ZIP exports separately stage receipts in /tmp (24 MiB default limit).
# For larger exports provision a private writable volume and set TMPDIR plus
# PARKRR_TAX_EXPORT_MAX_RECEIPT_MB in your own override. Concurrent exports
# share that capacity; a full spool aborts before download, without DB writes.
read_only: true
tmpfs:
# Bounded so a runaway temp write cannot consume host RAM up to mem_limit
# (tmpfs pages count toward the container's memory).
- /tmp:size=32m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
# Match the image's own non-root user (Dockerfile: adduser -u 10001 parkrr) and the
# /backups owner. Forcing a different uid (e.g. 65532) makes /backups unwritable and
# silently breaks scheduled backups.
user: "10001:10001"
mem_limit: 256m
pids_limit: 128
cpus: 1.0
db:
security_opt:
- no-new-privileges:true
# Drop everything, then add back only what the official Postgres entrypoint
# needs: chown the data dir (CHOWN/FOWNER/DAC_OVERRIDE) and drop to the
# postgres user via gosu (SETUID/SETGID). Remove this block if your Postgres
# image/entrypoint differs and fails to start.
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- SETGID
- SETUID
mem_limit: 512m
pids_limit: 256