Files
dejima-guard/docker-compose.example.yml
branderson 9d7d82c6d2 Rebuild the image, since nothing else will
There is no registry for this: the image is built from the Dockerfile in the
checkout. `docker compose up -d` reuses whatever image already exists, so after
a git pull it starts the old code and reports success - an update that silently
did not happen, on the program whose job is to notice things.

`--build` on both commands that need an image. `exec` does not.
2026-08-28 22:14:43 -07:00

108 lines
4.7 KiB
YAML

# The guard, as one service.
#
# AN EXAMPLE, not a compose file. Copy it to docker-compose.yml, edit it there,
# and start that - the copy is gitignored so your host and your URLs do not end
# up in a commit.
#
# Do not use it as an override. `docker compose up` reads docker-compose.yml
# and docker-compose.override.yml together and merges them, so an override
# leaves these example values in play rather than replacing them.
#
# As written it will not start: the host below is a placeholder the guard
# refuses, so this can never become a live config by being copied and
# forgotten.
services:
dejima-guard:
# Built here, not pulled: there is no registry for this. Which makes
# `--build` part of every command that starts it - `docker compose up -d`
# alone reuses the image it already has, so after a `git pull` it would run
# the old code and look like it had worked.
build: .
# image: gitbox.example.invalid/dejima/dejima-guard:latest
container_name: dejima-guard
restart: unless-stopped
environment:
# --- the machine being WATCHED, not the one this runs on ------------
#
# The devbox's hostname or address, as this container reaches it.
# Replace the placeholder: the guard refuses to start on CHANGE-ME.
DEJIMA_GUARD_DEVBOX_HOST: CHANGE-ME.example.invalid
# The account ON THE DEVBOX to log in as. Not root, and there is no
# default: the devbox runbook builds a machine with no root password
# and expects sudo from an ordinary account. The guard connects as that
# account and elevates for the two commands it runs.
DEJIMA_GUARD_DEVBOX_USER: your-devbox-account
# The private key, inside this container, to connect with. Mounted as a
# secret below rather than baked into the image.
DEJIMA_GUARD_SSH_KEY: /run/secrets/guard_key
# Where the devbox's host key is remembered. On the state volume,
# because a container filesystem is new every run - and without it,
# every collection fails host-key verification and reports the devbox
# unreachable. Already set in the image; here so it is visible.
DEJIMA_GUARD_SSH_KNOWN_HOSTS: /var/lib/dejima-guard/known_hosts
# --- where alerts go -----------------------------------------------
#
# Its OWN ntfy topic, not the one dejima pushes to. That URL lives on
# the devbox, so root there can publish to it: a compromised box could
# drown the topic or forge an all-clear. The token for this one goes in
# the mounted config, not here.
DEJIMA_GUARD_NTFY_URL: https://ntfy.example.invalid/devbox-alerts
# --- the dead-man's switch ------------------------------------------
#
# GET after a cycle that completed clean - an Uptime Kuma push monitor
# is the documented shape. Without it, a guard that dies looks exactly
# like a guard with nothing to report.
DEJIMA_GUARD_HEARTBEAT_URL: https://kuma.example.invalid/api/push/abcdef
# --- this container --------------------------------------------------
#
# Seconds between collections. Sets the dead-man's switch granularity
# and how long an intruder has to notice the monitoring and scrub.
DEJIMA_GUARD_INTERVAL: "900"
# Anything secret goes in the config file rather than here. Everything
# above is visible in `docker inspect` and to anything that can read
# /proc; a mounted secret is not. The guard reads the environment first
# and the file second, so this is the value that overrides.
DEJIMA_GUARD_CONF: /run/secrets/guard_config
# Mounted at /run/secrets/<name>, which is why CONF points there rather
# than at /etc. A `target:` naming an absolute path is a swarm feature and
# does not do what it looks like it does under plain `docker compose`.
secrets:
- guard_key
- guard_config
volumes:
# The baseline, the last report, and known_hosts. Losing this is not a
# clean slate: it is a guard that compares clean against everything and
# cannot verify the host it connects to.
- guard-state:/var/lib/dejima-guard
# It opens two outbound connections and writes one directory. Nothing here
# is a hardship, and this container holds an SSH key to a machine whose
# threat model says it may be owned.
read_only: true
tmpfs:
- /tmp
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
# NO PORTS. Not "none needed today" - the reason a container is an
# acceptable home for this is that nothing can connect to it.
volumes:
guard-state:
secrets:
guard_key:
file: ./secrets/guard_key # mode 0600, the private key
guard_config:
file: ./secrets/config # ntfy_token, and anything else secret