stage-8: deployable platform — Dockerfile + compose for company-network deploy
Lean python:3.12-slim platform image (cockpit + CLI + workers, 214 MB — no GPU, no model). docker-compose.yml runs cockpit + mock-cert on a persistent psyc-data volume. DATA_DIR is now overridable via PSYC_DATA_DIR so the container's data path is explicit. docs/deploy.md covers Proxmox hosting, first-run ingestion, and the honest caveats — no built-in auth (deploy behind the perimeter), the GPU model server is separate, egress-proxy config. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
# psyc platform image — cockpit + CLI + workers. No GPU, no model.
|
||||
# (The fine-tuned model runs separately; see Dockerfile.train + serve_model.py.)
|
||||
#
|
||||
# Build: docker build -t psyc:latest .
|
||||
# Run: docker compose up -d
|
||||
#
|
||||
# psyc has NO built-in authentication — deploy behind the company reverse
|
||||
# proxy / SSO / VPN, or firewall the ports to the SOC subnet. See docs/deploy.md.
|
||||
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PSYC_DATA_DIR=/data
|
||||
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml ./
|
||||
COPY src/ ./src/
|
||||
RUN pip install .
|
||||
|
||||
VOLUME /data
|
||||
EXPOSE 8767 8770
|
||||
|
||||
# Default service is the cockpit; docker-compose overrides the command for mock-cert.
|
||||
CMD ["psyc", "serve", "--host", "0.0.0.0", "--port", "8767"]
|
||||
37
docker-compose.yml
Normal file
37
docker-compose.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
# psyc — company-network deployment (cockpit + mock destination receiver).
|
||||
#
|
||||
# docker compose up -d --build
|
||||
#
|
||||
# WARNING: psyc has no built-in authentication. The cockpit exposes cases, the
|
||||
# ledger, and sealed-package metadata to anyone who can reach port 8767. Deploy
|
||||
# behind the company reverse proxy / SSO / VPN, or firewall the ports to the
|
||||
# SOC subnet. See docs/deploy.md.
|
||||
|
||||
services:
|
||||
cockpit:
|
||||
build: .
|
||||
image: psyc:latest
|
||||
command: ["psyc", "serve", "--host", "0.0.0.0", "--port", "8767"]
|
||||
ports:
|
||||
- "8767:8767"
|
||||
volumes:
|
||||
- psyc-data:/data
|
||||
restart: unless-stopped
|
||||
# Behind a company egress proxy, uncomment and set:
|
||||
# environment:
|
||||
# HTTPS_PROXY: http://proxy.corp:3128
|
||||
# HTTP_PROXY: http://proxy.corp:3128
|
||||
|
||||
mock-cert:
|
||||
image: psyc:latest
|
||||
command: ["psyc", "mock-cert", "--host", "0.0.0.0", "--port", "8770"]
|
||||
ports:
|
||||
- "8770:8770"
|
||||
volumes:
|
||||
- psyc-data:/data
|
||||
depends_on:
|
||||
- cockpit
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
psyc-data:
|
||||
79
docs/deploy.md
Normal file
79
docs/deploy.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# psyc — deployment
|
||||
|
||||
Deploying the psyc platform (cockpit + workers) as Docker containers — e.g. on a
|
||||
Proxmox-hosted VM in the company network.
|
||||
|
||||
## Read this before deploying
|
||||
|
||||
- **No built-in authentication.** The cockpit exposes cases, the ledger, and
|
||||
sealed-package metadata to anyone who can reach port 8767. Deploy it **behind
|
||||
the company reverse proxy / SSO / VPN**, or firewall the ports to the SOC
|
||||
subnet. Do not expose 8767 to the open network. (If you want in-app auth
|
||||
instead of relying on the perimeter, that's a feature to add — not present today.)
|
||||
- **The live model is separate.** This image has no GPU and no torch. The
|
||||
fine-tuned-model bot needs `serve_model.py` running in the CUDA container on a
|
||||
GPU host (Proxmox GPU passthrough to a VM). Without it the Classifier bot
|
||||
falls back to rules — the platform works fine, just rules-only.
|
||||
- **Outbound network.** Scoutline (URLhaus / CISA KEV / Feodo) and Mapline
|
||||
(ip-api.com) make outbound HTTPS. Behind a company egress proxy, set
|
||||
`HTTPS_PROXY` / `HTTP_PROXY` in the container environment (see the commented
|
||||
block in `docker-compose.yml`).
|
||||
- **mock-cert is a stand-in.** It accepts submissions for testing — it is not a
|
||||
real destination. Wire real CERT / MISP / abuse endpoints (and their
|
||||
credentials, per `docs/dossier.md` §18) before relying on routing in production.
|
||||
|
||||
## Proxmox
|
||||
|
||||
Docker is not native to Proxmox. Run it inside a Proxmox **VM** (recommended —
|
||||
clean isolation, simplest Docker support) or a privileged LXC. Install Docker +
|
||||
the Compose plugin in that guest, give it outbound network for the feeds, then
|
||||
deploy as below. The GPU inference server, if used, needs a separate VM with
|
||||
GPU passthrough.
|
||||
|
||||
## Deploy
|
||||
|
||||
```bash
|
||||
git clone ssh://git@gitea.neuronetz.ai:222/m17hr1l/psyc.git
|
||||
cd psyc
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Starts two containers from one `psyc:latest` image:
|
||||
|
||||
| Service | Port | Role |
|
||||
|---|---|---|
|
||||
| `cockpit` | 8767 | operator UI |
|
||||
| `mock-cert` | 8770 | stand-in destination receiver (testing) |
|
||||
|
||||
The sqlite db, sealed packages, and recipient keys persist in the `psyc-data`
|
||||
named volume — they survive container restarts and rebuilds.
|
||||
|
||||
## First run
|
||||
|
||||
The schema is created on cockpit startup, but there are no cases until you
|
||||
ingest. Run inside the container:
|
||||
|
||||
```bash
|
||||
docker compose exec cockpit psyc fetch-all
|
||||
docker compose exec cockpit psyc classify-all
|
||||
docker compose exec cockpit psyc map-all
|
||||
```
|
||||
|
||||
Keep it ingesting by scheduling `fetch-all` — a host cron entry calling
|
||||
`docker compose exec cockpit psyc fetch-all`, e.g. hourly.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The `psyc-data` volume is preserved across updates.
|
||||
|
||||
## Health
|
||||
|
||||
```bash
|
||||
curl http://<host>:8767/healthz # cockpit
|
||||
curl http://<host>:8770/healthz # mock-cert
|
||||
```
|
||||
@@ -1,9 +1,12 @@
|
||||
"""psyc — defensive CTI routing & evidence-sealing platform."""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
DATA_DIR = PROJECT_ROOT / "data"
|
||||
# PSYC_DATA_DIR lets a container/deployment set the data path explicitly;
|
||||
# otherwise data lives next to the repo (works for an editable install).
|
||||
DATA_DIR = Path(os.environ["PSYC_DATA_DIR"]) if os.environ.get("PSYC_DATA_DIR") else PROJECT_ROOT / "data"
|
||||
|
||||
Reference in New Issue
Block a user