Operate

Deployment & security

gmonk runs entirely in your own infrastructure — one Docker image plus a Postgres store. No code, prompts, or data leave your network.

Run it

gmonk ships as one Docker image; you provide a small compose file that runs it alongside Postgres. Grab the ready-made one (docker-compose.yml) into an empty directory:

bash
curl -O https://gmonk.dev/docker-compose.yml
docker compose up   # Postgres + one-shot schema migration + review UI

# pin/upgrade the version:
#   GMONK_IMAGE=gmonkdev/gmonk:0.5.0 docker compose up

The review UI serves on http://127.0.0.1:4319, bound to loopback. The compose file only orchestrates the published image plus a stock Postgres — nothing to build. See the install guide for the full first-run walk-through.

What the compose file sets up

  • postgres — gmonk's own store (demo credentials gmonk:gmonk — override for production).
  • migrate — a one-shot that applies the schema, then exits; the UI waits for it.
  • gmonk — the review UI, bound to 127.0.0.1:4319, with a durable volume for file before-images and a state volume for the auto-generated capture-hook token.

To protect a database, add gmonk protect --backend-ref … (see the install guide); to capture a Claude Code session, run docker compose run --rm -v "$HOME/.claude:/root/.claude" gmonk install-hook --scope user.

The two-database model

gmonk keeps its own store (metadata + before-images, GMONK_DATABASE_URL) separate from the target you protect. It never installs its tables in your database. For secret hygiene, a run records only the env-var name of the target URL — never the URL itself.

Backend TLS

A terminating proxy authenticates to your database as gmonk's privileged role, so its password crosses that hop. gmonk connects to a remote target over mandatory TLS by default (host-aware: remote → require, loopback → prefer) and refuses to send credentials in cleartext.

bash
GMONK_PG_BACKEND_TLS=require       # disable | prefer | require | verify
GMONK_PG_BACKEND_CA=/path/ca.pem   # pin a CA for verify
# (GMONK_MYSQL_BACKEND_TLS / _CA for MySQL; a per-URL ?sslmode= wins)

Review-UI auth & SSO

The UI can apply reversals, so it refuses to bind off loopback without auth. Options, strongest first:

  • SSO / OIDC — Okta, Google, Azure AD/Entra, Auth0, Keycloak. Authorization-Code + PKCE, group→role mapping, short-lived session cookies, immediate central deprovisioning. Validate with gmonk sso-check.
  • Per-user accountsgmonk users add …, roles viewer/operator/admin enforced server-side.
  • Shared tokenGMONK_WEB_TOKEN; every API call must present it. The mutating reverse endpoint also requires a custom header (CSRF-safe).

Make gmonk the only way in

Capture is only complete if the agent can't sidestep it. gmonk enforce revokes the agent account's direct DML so the proxy is the sole path — for Postgres (roles) and MySQL (multi-level grants).

bash
gmonk enforce --agent-role agent_rw

On a protected table, even a write that bypasses the gateway is still captured, flagged, and reversible — and fires an out_of_band alert.

Tenant isolation, object perimeter, retention

  • Row-level security on every table (FORCE). For real isolation, connect as the non-superuser gmonk_app role, not the owner.
  • Object-store allowlistGMONK_OBJECT_ALLOW_BUCKETS fail-closed on buckets/prefixes; defense-in-depth over IAM scoping.
  • Redaction — tool arguments are scrubbed for secrets/PII before they're written.
  • Retention / GCgmonk gc --schedule --every 24h (or in-process via gmonk protect --gc-every) mark-sweeps unreferenced before-images. Deletion is opt-in.
  • Auditprotect-db, unprotect-db, and every reverse are recorded in gmonk_audit; the action hash chain makes tampering evident.
Store is a hard dependency. A captured write fails closed if the store is unreachable — run the Postgres store HA. Don't ship the demo gmonk:gmonk credentials.