Files
sshkeyvault/docker-compose.yml
T
florian.wildeandClaude Opus 5.5 7bb2ca6a51 feat(protokoll): Syslog-Sender nach RFC 5424 ohne Abhaengigkeit (#027)
Die Kopie beim Syslog-Server ist der vom sshkv-Host unabhaengige Beleg:
wer die Datenbank uebernimmt, kann die Hash-Kette neu rechnen, aber nicht
zurueckholen, was schon beim Syslog liegt. Eigene kleine Implementierung
mit node:dgram/node:net statt einer Bibliothek, weil das Format
ueberschaubar ist und jede Abhaengigkeit im Sicherheitskern zaehlt.

Strukturierte Daten werden nach RFC 5424 escaped und begrenzt (2048 Byte),
Severity folgt dem Ergebnis, Facility standardmaessig authpriv. Der Sender
wirft nie und meldet Fehler hoechstens einmal je Minute, damit ein
ausgefallener Syslog-Server weder Aktionen verhindert noch das Log flutet.
Web und Worker bekommen die Variablen, weil beide protokollieren.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:47:30 +02:00

131 lines
4.8 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SSHKeyVault – Betrieb mit Weboberflaeche, Worker und Datenbank.
# 1. cp .env.example .env und Werte eintragen (mindestens SSHKV_APP_SECRET, POSTGRES_PASSWORD,
# SSHKV_APP_URL, SSHKV_BREAKGLASS_PASSWORD)
# 2. Master-Key erzeugen (nur fuer den Worker lesbar, Container-Benutzer 1001):
# mkdir -p geheim && head -c 32 /dev/urandom > geheim/master.key
# sudo chown 1001:1001 geheim/master.key && sudo chmod 400 geheim/master.key
# (oder SSHKV_WORKER_USER auf den Eigentuemer der Datei setzen)
# 3. docker compose up -d
# Nur im internen Netz/VPN betreiben und einen Reverse Proxy mit TLS davorsetzen (docs/betrieb).
name: sshkv
services:
db:
image: postgres:17-alpine
container_name: sshkv-db
restart: unless-stopped
environment:
POSTGRES_USER: sshkv
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt in der .env}
POSTGRES_DB: sshkv
volumes:
- datenbank:/var/lib/postgresql/data
networks: [datenbank]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U sshkv"]
interval: 10s
timeout: 5s
retries: 10
# Laeuft einmal je Start: Schema einspielen, Notfall-Admin und Vorlagen anlegen.
migrate:
build:
context: .
target: bauen
image: sshkv-migrate
restart: "no"
depends_on:
db:
condition: service_healthy
command: ["sh", "-c", "pnpm prisma migrate deploy && pnpm prisma db seed"]
environment:
DATABASE_URL: postgresql://sshkv:${POSTGRES_PASSWORD}@db:5432/sshkv?schema=public
SSHKV_BREAKGLASS_USER: ${SSHKV_BREAKGLASS_USER:-notfall}
SSHKV_BREAKGLASS_PASSWORD: ${SSHKV_BREAKGLASS_PASSWORD:-}
networks: [datenbank]
web:
build: .
image: sshkv
container_name: sshkv-web
restart: unless-stopped
depends_on:
migrate:
condition: service_completed_successfully
environment:
DATABASE_URL: postgresql://sshkv:${POSTGRES_PASSWORD}@db:5432/sshkv?schema=public
SSHKV_APP_URL: ${SSHKV_APP_URL:?SSHKV_APP_URL fehlt in der .env}
SSHKV_APP_SECRET: ${SSHKV_APP_SECRET:?SSHKV_APP_SECRET fehlt in der .env}
SSHKV_OIDC_ISSUER: ${SSHKV_OIDC_ISSUER:-}
SSHKV_OIDC_CLIENT_ID: ${SSHKV_OIDC_CLIENT_ID:-}
SSHKV_OIDC_CLIENT_SECRET: ${SSHKV_OIDC_CLIENT_SECRET:-}
SSHKV_OIDC_NAME: ${SSHKV_OIDC_NAME:-authentik}
SSHKV_OIDC_GROUP_ADMIN: ${SSHKV_OIDC_GROUP_ADMIN:-sshkv-admins}
SSHKV_OIDC_GROUP_OPERATOR: ${SSHKV_OIDC_GROUP_OPERATOR:-sshkv-operators}
SSHKV_OIDC_GROUP_READER: ${SSHKV_OIDC_GROUP_READER:-sshkv-readers}
# Syslog-Kopie des Protokolls (#027) – optional, leer heisst aus.
SSHKV_SYSLOG_HOST: ${SSHKV_SYSLOG_HOST:-}
SSHKV_SYSLOG_PORT: ${SSHKV_SYSLOG_PORT:-514}
SSHKV_SYSLOG_PROTOKOLL: ${SSHKV_SYSLOG_PROTOKOLL:-udp}
SSHKV_SYSLOG_APPNAME: ${SSHKV_SYSLOG_APPNAME:-sshkv}
SSHKV_SYSLOG_FACILITY: ${SSHKV_SYSLOG_FACILITY:-authpriv}
# Absichtlich KEIN Master-Key: eine Luecke im Webprozess allein entschluesselt keine
# Private Keys. Nach aussen braucht er nur den OIDC-Anbieter.
ports:
- "${SSHKV_BIND:-127.0.0.1}:${SSHKV_PORT:-3400}:3400"
networks: [datenbank, aussen]
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3400/api/gesundheit"]
interval: 30s
timeout: 5s
retries: 5
start_period: 20s
worker:
image: sshkv
container_name: sshkv-worker
restart: unless-stopped
command: ["./start.sh", "worker"]
# Muss die Master-Key-Datei lesen duerfen (0400). Standard ist der Benutzer im Abbild;
# alternativ den Eigentuemer der Datei eintragen, z. B. SSHKV_WORKER_USER=1000:1000.
user: "${SSHKV_WORKER_USER:-1001:1001}"
depends_on:
migrate:
condition: service_completed_successfully
web:
condition: service_started
environment:
DATABASE_URL: postgresql://sshkv:${POSTGRES_PASSWORD}@db:5432/sshkv?schema=public
SSHKV_APP_SECRET: ${SSHKV_APP_SECRET}
SSHKV_MASTER_KEY_FILE: /run/secrets/master_key
SSHKV_SYNC_CRON: ${SSHKV_SYNC_CRON:-30 2 * * *}
# Syslog-Kopie des Protokolls (#027) – optional, leer heisst aus.
SSHKV_SYSLOG_HOST: ${SSHKV_SYSLOG_HOST:-}
SSHKV_SYSLOG_PORT: ${SSHKV_SYSLOG_PORT:-514}
SSHKV_SYSLOG_PROTOKOLL: ${SSHKV_SYSLOG_PROTOKOLL:-udp}
SSHKV_SYSLOG_APPNAME: ${SSHKV_SYSLOG_APPNAME:-sshkv}
SSHKV_SYSLOG_FACILITY: ${SSHKV_SYSLOG_FACILITY:-authpriv}
secrets:
- master_key
# Der Worker braucht die Datenbank und den Weg zu den Hosts.
networks: [datenbank, aussen]
healthcheck:
test: ["CMD-SHELL", "pgrep -f dist/worker.mjs > /dev/null"]
interval: 60s
timeout: 5s
retries: 3
secrets:
master_key:
file: ${SSHKV_MASTER_KEY_HOST_FILE:-./geheim/master.key}
networks:
# Die Datenbank hat keinen Weg nach draussen.
datenbank:
internal: true
aussen: {}
volumes:
datenbank: