202 lines
5.9 KiB
YAML
202 lines
5.9 KiB
YAML
# =============================================================================
|
|
# Attack/Defence stack - all services, one file.
|
|
#
|
|
# Deployed by .gitea/workflows/deploy.yaml to $STACK_DIR (/opt/stacks/myapp).
|
|
# Build contexts are relative to this file, i.e. the repo root.
|
|
#
|
|
# TWO RULES THIS FILE MUST OBEY (the workflow enforces both and will refuse
|
|
# to deploy otherwise):
|
|
#
|
|
# 1. Every published port is pinned to ${WG_IP}. A bare "1338:8080" binds
|
|
# 0.0.0.0, and Docker's iptables chain is evaluated before ufw's INPUT
|
|
# chain -- so `ufw deny 1338` would NOT close it. Never omit the host_ip.
|
|
#
|
|
# 2. Anything that must survive a deploy lives either in a named volume or
|
|
# under a `data/` directory. The workflow rsyncs the repo over the host
|
|
# with --delete and only `data/` and `.env` are excluded from that.
|
|
# A bind mount anywhere else gets wiped on every push.
|
|
#
|
|
# Required in /opt/stacks/myapp/.env (host-only, never in git) - see
|
|
# .env.example:
|
|
# WG_IP=10.x.x.x # the WireGuard address to publish on
|
|
# SECRET_KEY=... # puhososik JWT signing key
|
|
# =============================================================================
|
|
|
|
name: myapp
|
|
|
|
x-common: &common
|
|
restart: unless-stopped
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
services:
|
|
# ------------------------------------------------------------ chessstars
|
|
# Go + cgo engine. Listens on :8080 (PORT), state in /data.
|
|
chessstars:
|
|
<<: *common
|
|
build: ./chessstars
|
|
pids_limit: 256
|
|
mem_limit: 256M
|
|
cpus: 1.0
|
|
networks: [chessstars_net]
|
|
ports:
|
|
- "${WG_IP}:1338:8080"
|
|
volumes:
|
|
- ./chessstars/data:/data
|
|
environment:
|
|
AUTH_CLEANUP_TTL: 60m
|
|
AUTH_CLEANUP_INTERVAL: 5m
|
|
GAME_CLEANUP_FINISHED_TTL: 30m
|
|
GAME_CLEANUP_OPEN_TTL: 60m
|
|
GAME_CLEANUP_INTERVAL: 5m
|
|
|
|
# The cleaners below only rm files on a mounted volume; none of them needs a
|
|
# socket. network_mode: none removes them as a pivot if a service falls.
|
|
chessstars_course_cleaner:
|
|
<<: *common
|
|
image: c4tbuts4d/dedcleaner:latest
|
|
network_mode: none
|
|
pids_limit: 32
|
|
mem_limit: 32M
|
|
cpus: 0.1
|
|
volumes:
|
|
- ./chessstars/data/courses:/courses
|
|
environment:
|
|
DELETE_AFTER: 60m
|
|
SLEEP: 5m
|
|
DIRS: /courses
|
|
|
|
# --------------------------------------------------------------- example
|
|
# Flask, :5000. Notes moved from ./notes to ./example/data/notes so the
|
|
# rsync --delete in the deploy stops wiping them on every push (rule 2).
|
|
example:
|
|
<<: *common
|
|
build: ./example
|
|
pids_limit: 256
|
|
mem_limit: 64M
|
|
cpus: 0.5
|
|
networks: [example_net]
|
|
ports:
|
|
- "${WG_IP}:1337:5000"
|
|
volumes:
|
|
- ./example/data/notes:/app/notes
|
|
|
|
example_cleaner:
|
|
<<: *common
|
|
image: c4tbuts4d/dedcleaner:latest
|
|
network_mode: none
|
|
pids_limit: 32
|
|
mem_limit: 32M
|
|
cpus: 0.1
|
|
volumes:
|
|
- ./example/data/notes:/notes
|
|
environment:
|
|
DELETE_AFTER: 30m
|
|
SLEEP: 30m
|
|
DIRS: /notes
|
|
|
|
# ------------------------------------------------------------- hard_exam
|
|
# Flask, :1337. src/db.py resolves the DB to <src>/data/data.db -> the
|
|
# container path is /app/data/data.db, so /app/data is what gets persisted.
|
|
# The old `./src/data.db:/app/data.db` mount pointed at a path the app never
|
|
# opens, and Docker would have created it as a directory.
|
|
hard_exam:
|
|
<<: *common
|
|
build: ./hard_exam
|
|
pids_limit: 128
|
|
mem_limit: 256M
|
|
cpus: 0.5
|
|
networks: [hard_exam_net]
|
|
ports:
|
|
- "${WG_IP}:51234:1337"
|
|
volumes:
|
|
- ./hard_exam/data:/app/data
|
|
|
|
# ------------------------------------------------------------- puhososik
|
|
# Flask, :5000. SECRET_KEY signs JWTs - app.py falls back to
|
|
# 'default_secret_for_local_test' if unset, which would let anyone forge a
|
|
# token, so fail the deploy loudly instead of booting insecure.
|
|
puhososik:
|
|
<<: *common
|
|
build: ./puhososik
|
|
pids_limit: 256
|
|
mem_limit: 128M
|
|
cpus: 0.5
|
|
networks: [puhososik_net]
|
|
ports:
|
|
- "${WG_IP}:5252:5000"
|
|
volumes:
|
|
- ./puhososik/data:/app/data
|
|
environment:
|
|
SECRET_KEY: ${SECRET_KEY:?set SECRET_KEY in /opt/stacks/myapp/.env}
|
|
|
|
puhososik_cleaner:
|
|
<<: *common
|
|
build: ./puhososik/cleaner
|
|
network_mode: none
|
|
pids_limit: 32
|
|
mem_limit: 32M
|
|
cpus: 0.1
|
|
depends_on:
|
|
- puhososik
|
|
volumes:
|
|
- ./puhososik/data:/data
|
|
environment:
|
|
DB_PATH: /data/puhososik.db
|
|
DELETE_AFTER: 1800
|
|
SLEEP: 300
|
|
BATCH_SIZE: 400
|
|
|
|
# ----------------------------------------------- reverse_and_polish (pwn)
|
|
# socat -> patchelf'd binary as uid 1337. entrypoint.sh runs its own cleaner
|
|
# loop over /data/ctf.db, so no sidecar and nothing to persist here.
|
|
reverse_and_polish:
|
|
<<: *common
|
|
build: ./reverse_and_polish
|
|
pids_limit: 256
|
|
mem_limit: 256M
|
|
cpus: 1.0
|
|
networks: [reverse_and_polish_net]
|
|
ports:
|
|
- "${WG_IP}:7845:1337"
|
|
|
|
# --------------------------------------------------------- skibidimonitor
|
|
# Rust/axum, :12345. BIND_ADDR is 0.0.0.0 *inside* the container - that is
|
|
# correct and unrelated to rule 1; the host_ip on the port mapping is what
|
|
# keeps it off the public internet.
|
|
skibidimonitor:
|
|
<<: *common
|
|
build: ./skibidimonitor
|
|
pids_limit: 256
|
|
mem_limit: 256M
|
|
cpus: 1.0
|
|
networks: [skibidimonitor_net]
|
|
ports:
|
|
- "${WG_IP}:12345:12345"
|
|
volumes:
|
|
- skibidi-data:/app/data
|
|
environment:
|
|
BIND_ADDR: 0.0.0.0:12345
|
|
DATABASE_URL: sqlite:///app/data/skibidi.db?mode=rwc
|
|
SESSION_TTL_SECONDS: 300
|
|
SNAPSHOT_CACHE_TTL_SECONDS: 300
|
|
|
|
# One network per service instead of the shared default bridge: without this
|
|
# every container resolves and reaches every other one by name, so a single RCE
|
|
# hands the attacker the whole stack.
|
|
networks:
|
|
chessstars_net:
|
|
example_net:
|
|
hard_exam_net:
|
|
puhososik_net:
|
|
reverse_and_polish_net:
|
|
skibidimonitor_net:
|
|
|
|
volumes:
|
|
skibidi-data:
|