# 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} # Nur zur Anzeige unter /einstellungen; ausgefuehrt werden die Zeitplaene im Worker. SSHKV_SYNC_CRON: ${SSHKV_SYNC_CRON:-30 2 * * *} SSHKV_MELDUNG_CRON: ${SSHKV_MELDUNG_CRON:-0 7 * * *} # 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} # Benachrichtigungen (#028): taegliche Zusammenfassung; Links in den Nachrichten zeigen # auf SSHKV_APP_URL. Den Weg zu Mailserver und Webhook-Ziel hat der Worker ueber "aussen". SSHKV_MELDUNG_CRON: ${SSHKV_MELDUNG_CRON:-0 7 * * *} SSHKV_APP_URL: ${SSHKV_APP_URL} secrets: - master_key # Der Worker braucht die Datenbank und den Weg zu den Hosts (und zu Mailserver/Webhook). 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: