Security operations & deployment hardening¶
How a GaugeWright deployment is configured and monitored to meet its security posture. This is the operator-facing companion to the controls built into the product — it names the knobs you must set for a hosted/enterprise deployment and the signals you must monitor.
Desktop/solo installs need none of this: they run on the operator's own machine, on loopback, with sensible defaults. The settings below apply when you host the control plane for others.
Deployment hardening checklist (hosted / enterprise)¶
Set these before exposing a control plane beyond loopback. Several are fail-loud gates — the process refuses to start rather than run insecurely.
| Setting | Purpose | Enforcement |
|---|---|---|
GAUGEWRIGHT_ALLOW_NETWORK_HTTP=1 |
Acknowledge a non-loopback bind (the API has no cross-authority auth of its own — see below). | Refuses to start without it (FED-2). |
GAUGEWRIGHT_TLS_TERMINATED=1 |
Confirm a TLS-terminating reverse proxy fronts the plain-HTTP API. | Non-loopback bind refused without it. Every response also carries HSTS (ENTSEC-7). |
GAUGEWRIGHT_HARDENED=1 |
Declare a hosted/hardened deployment. | Requires crash-safe durability below. Warns if at-rest encryption is unconfigured (SECAUD-9). |
GAUGEWRIGHT_SQLITE_SYNCHRONOUS=FULL |
Crash-durable persistence (fsync per commit) so recent admits survive an OS crash. | Required under GAUGEWRIGHT_HARDENED=1 (SECAUD-9). |
GAUGEWRIGHT_AUDIT_READS=1 |
Also record reads of project-scoped data (transcripts/files/resources) to the audit trail — "who read this client's data". | Opt-in (reads are high-volume). Off by default (SECAUD-4). |
GAUGEWRIGHT_ENCRYPT_CONTENT=1 |
Encrypt transcript content at rest under per-engagement keys (SECAUD-9). Deleting a chat crypto-erases its content (SECAUD-6, GDPR erasure). |
Off by default. Dev uses a local KEK. A hosted deployment swaps in the KMS KeyWrap adapter. |
Authentication boundary¶
The control-plane HTTP API authenticates org members (per-request, fail-closed) once an identity provider is configured (enterprise mode). It has no cross-authority auth — peers federate over the broker with cert-pinned TLS, not this API. So a hosted control plane must sit behind:
- a TLS-terminating reverse proxy (the API speaks plain HTTP, tokens and transcripts must not cross the wire in cleartext), and
- an edge rate-limiter / WAF. In-process throttling exists as defense-in-depth (for example, the SCIM bearer locks out after repeated failures, SECAUD-8), but the primary brute-force and abuse control is the edge. Configure per-IP request limits on the auth and data routes.
Encryption at rest¶
Transcript content can be encrypted at rest under per-engagement keys by setting
GAUGEWRIGHT_ENCRYPT_CONTENT=1 (SECAUD-9). Deleting a chat then crypto-erases
its content — the key is destroyed, the retained ciphertext is unrecoverable
(SECAUD-6, GDPR right-to-erasure), the append-only log intact. Metadata/lifecycle
records remain plaintext (content-only by design).
The per-engagement DEKs are wrapped by a KEK. Selecting the KMS is creds-only — no code change:
- Dev / single-machine: unset
GAUGEWRIGHT_CONTENT_KEK_ID⇒ a persisted local KEK. - Hosted (KMS): set
GAUGEWRIGHT_CONTENT_KEK_IDto the Key Vault KEK id (https://<vault>.vault.azure.net/keys/<name>/<version>) and the Azure Crypto User service-principal credsAZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CLIENT_SECRET. The control plane then wraps every DEK through Key VaultwrapKey/unwrapKey(SEC-4). Fail-loud: if the KEK id is set but the creds are incomplete, or the vault is unreachable at startup, the process refuses to start rather than silently downgrading to a local KEK.
For full at-rest coverage of the rest of the data plane (and git-blob workspace files),
also run on an encrypted volume / KMS-backed disk. GAUGEWRIGHT_HARDENED=1 warns if
no at-rest KEK is configured.
Monitoring & alerting¶
The product emits the signals. Your monitoring stack consumes and alerts on them.
- Audit integrity.
GET /admin/audit/verifyreturns the hash-chain integrity of the governance audit log ({ok, entries, head, broken_at, anchored}, SECAUD-2). The head is signed by the governance key on every append, soverifycatches not just mid-chain edits but also tail truncation, last-entry edits, and a forged checkpoint. Alert ifokis false (history was altered) or ifanchoredis false when you run signed (the signed anchor is missing). For belt-and-suspenders against a full dual-wipe of the log and its checkpoints, also export theheadto an external witness. - SIEM export health. The audit SIEM exporter retries a bounded backlog and
exposes
failure_count(export attempts that failed — the SIEM-unhealthy rate),dropped_count(entries lost to backlog overflow — an actual gap), andpending_count(export lag) (SECAUD-3). Alert on a risingfailure_countor anydropped_count. - Audit stream. Stream the audit log to your SIEM (Splunk HEC / Datadog / a webhook) and build detections there: a spike of role changes, repeated auth failures, an export-gate denial, or off-hours access.
- Liveness.
GET /healthis the readiness/liveness probe.
Terraform state & secrets¶
Infrastructure (the infra/ tree in the private gaugewright-cloud repo) is
provisioned with Terraform. Never commit
*.tfstate — it contains plaintext provider secrets and is gitignored. For any
shared/production infrastructure:
- Use a remote state backend (Azure Blob, S3, Terraform Cloud) with encryption at rest and access control, not local state files.
- Rotate any credential that has ever appeared in a local state file or other unencrypted artifact, even if it was never committed.
- Keep the subprocessor list current as infrastructure changes.
See also the incident-response runbook.