# Prompt Guard: customer-hosted managed gateway

This package performs text inspection inside your environment, then calls fixed OpenAI, Anthropic or Gemini HTTPS endpoints. Raw prompts never pass through Workflow Inspector's hosted service. It is a standalone customer-operated deployment, separate from hosted subscription quotas and account policies. The same deterministic scanner is used by both deployments.

## Delivered controls

- Mutual TLS plus a separate bearer credential bound to the client certificate fingerprint.
- Central administrator-owned policy, expiring identities, per-identity provider permissions, revocation by removal, and a global `enabled: false` emergency stop. Policy is validated on every request and rechecked after body intake. Already-forwarded requests cannot be recalled.
- Upstream credentials mounted on the gateway only; workloads receive no provider keys. Only fixed provider destinations and non-streaming text chat are accepted. No general-purpose proxy, CONNECT tunnel, tools or browser interception. The optional enterprise package extracts supported files, image text and audio locally before the same text-policy checks.
- Maximum 16 KiB combined text, 32 KiB HTTP JSON body, 4,096 output tokens, 16 concurrent requests and 60 requests/minute/identity/instance.
- Signed, hash-linked metadata journal with disk synchronization before forwarding. Failed audit storage stops new forwarding. An accepted request without a terminal outcome needs investigation; never automatically retry it because the provider may already have processed it.
- Policy-load evidence contains a policy digest, version and enabled state, not the policy terms or credential hashes themselves. Request evidence contains actor ID, request ID, provider, detector counts and scanner version, not prompts, responses or provider secrets. Invalid authentication and malformed requests are rejected but are not individually journaled.

## Obtain and build

Download `managed-gateway.mjs`, `audit-journal.mjs`, `scanner.mjs`, `manage-gateway.mjs`, `verify-audit.mjs`, `verify-egress.mjs`, `Gateway.Dockerfile`, and `gateway-kubernetes.yaml` into one local directory. The deployment page links each file. Also download enterprise-directory.mjs, enterprise-oidc.mjs, content-inspection.mjs and extract-content.py, which are runtime imports even when optional features are disabled. Node 22+ and your existing TLS certificate authority are required.

```sh
node manage-gateway.mjs init ./guard-config
```

This creates an initially **disabled** policy and a unique Ed25519 audit keypair. Do not regenerate keys on restart. Keep `audit-public.pem` independently, off the gateway. Back up the private key securely. Never publish this directory or include it in a container image.

Provision these through your organization's existing PKI/secret manager:

- `tls-cert.pem` and `tls-key.pem`: server certificate with SAN `prompt-guard.guard-system.svc` (and any actual client-facing hostname).
- `client-ca.pem`: trusted client-issuing CA bundle. Use client certificates with clientAuth usage, one per identity. Use your existing certificate issuance/renewal controls; do not share a certificate/private key among employees.
- A matching client certificate and key for each workload, delivered separately from the bearer token.
- `openai.key`, `anthropic.key`, `gemini.key`: upstream API keys. Enable only providers you use. Remove unused provider environment entries from the manifest; do not mount empty dummy files.

Add an identity with its **public** client certificate:

```sh
node manage-gateway.mjs actor ./guard-config orders-service ./orders-client.pem openai,anthropic 30
```

A token is written once to `guard-config/orders-service.token`, never printed. Deliver it securely to that workload, along with its client key/certificate. The certificate must remain valid for the chosen credential lifetime. Keep token files OUT of the gateway Secret; it needs only the hashes in `policy.json`.

Edit `policy.json`: choose `block` or `redact`, add up to 50 literal terms of 3–120 characters, and set `enabled: true` when ready. Begin the pilot in `block` mode. Change `version` for each rollout. Publish local updates with atomic file replacement, not partial in-place writes. Remove an actor to revoke it; issue a fresh token and certificate for replacement. Invalid/missing policy fails closed.

## Container and Kubernetes installation

```sh
docker build -f Gateway.Dockerfile -t YOUR_REGISTRY/prompt-guard:VERSION .
```

Push through your registry and pin the reviewed image digest in `gateway-kubernetes.yaml`. The Dockerfile copies runtime and administration modules plus console assets, never keys. The runtime runs as UID/GID 10001 with a read-only root filesystem in the supplied manifest.

Create `guard-system` and `guard-workloads` namespaces first (the manifest contains their definitions). In `guard-system`, create:

1. Secret `guard-policy` with just the key `policy.json`.
2. Secret `guard-secrets` with `tls-key.pem`, `tls-cert.pem`, `client-ca.pem`, `audit-private.pem` and each enabled provider's key file.

For example, after creating the namespace:

```sh
kubectl -n guard-system create secret generic guard-policy --from-file=policy.json=./guard-config/policy.json
kubectl -n guard-system create secret generic guard-secrets \
  --from-file=tls-key.pem --from-file=tls-cert.pem --from-file=client-ca.pem \
  --from-file=audit-private.pem=./guard-config/audit-private.pem \
  --from-file=openai.key --from-file=anthropic.key --from-file=gemini.key
kubectl apply -f gateway-kubernetes.yaml
```

Use your standard secret-management pipeline for updates. Mounted Secret changes are eventually propagated by Kubernetes; revocation takes effect when the new file reaches the gateway. For immediate emergency containment, scale the gateway to zero or block its network egress. TLS certificates, audit keys and provider keys are loaded at startup: restart for rotation, retaining the audit key for the current journal.

Use one replica with Recreate and a persistent volume. The exclusive `.lock` file prevents concurrent audit writers. A crash intentionally leaves the lock: stop every writer, verify and archive/checkpoint the journal, investigate any accepted-only requests, then remove the stale lock and restart. Never delete a lock while a process may still be writing. Do not horizontally scale this single-writer package.

Protected workloads must run in `guard-workloads` (or receive equivalent policies) and use:

`https://prompt-guard.guard-system.svc:8443/v1/chat/completions`

Configure the HTTPS client with the server CA, client certificate/private key, and bearer token. Do not disable certificate verification. Set JSON `provider` to `openai`, `anthropic` or `gemini`; use that provider's actual model identifier. Request/response schema is Chat Completions text format. The gateway chooses the provider credential; do not supply upstream credentials from workloads.

## Verify enforcement before rollout

Your CNI must enforce Kubernetes NetworkPolicy. Review **all** policies selecting the workload: policies are additive, and an existing allow-all egress policy defeats this template. Restrict workload operators from altering namespaces, labels, policies, gateway Secrets or deployments. The restricted namespace admission policy excludes privileged/host-network workloads. The DNS rule assumes kube-dns labels and must match your resolver; DNS resolution is still allowed and this package does not prevent DNS tunneling.

The workload namespace policy permits only gateway TLS and cluster DNS. Other business dependencies need explicit administrator-reviewed allow rules. The gateway itself can reach public IPv4 HTTPS; application code restricts requests to the three provider hosts. This is not network-layer hostname filtering for a compromised gateway. Add your existing egress firewall/FQDN policy for that requirement. Do not treat cluster/node administrator compromise as covered.

Run `verify-egress.mjs` **inside each representative protected workload/network**, with the client materials mounted:

```sh
GUARD_URL=https://prompt-guard.guard-system.svc:8443/v1/chat/completions \
GUARD_TOKEN_FILE=/client/service.token \
GUARD_SERVER_CA_FILE=/client/server-ca.pem \
GUARD_CLIENT_CERT_FILE=/client/cert.pem \
GUARD_CLIENT_KEY_FILE=/client/key.pem node verify-egress.mjs
```

It requires the synthetic email canary to be blocked, rejects a bad bearer token, and attempts direct HTTPS connections to all three provider hosts without provider credentials. Save the result with the deployment manifest/image digest and approved policy version. Connection failures are observations, not proof of every possible bypass. Also verify pod restart persistence, revoked/expired identities, audit storage failure, your intended clean request with an authorized provider key, and unsupported input rejection. No actual customer network or live provider request has been validated by the repository's synthetic tests.

This network policy does not manage laptops, native desktop apps, consumer ChatGPT/Claude/Gemini websites, unmanaged devices or other namespaces. Use the separate managed-browser example and your organization's endpoint/network controls, then test each surface. Do not advertise company-wide coverage until those installations and tests are complete.

## Audit verification, export, retention and incidents

```sh
node verify-audit.mjs /audit/events.jsonl /trusted/audit-public.pem > checkpoint.json
node verify-audit.mjs /archive/events.jsonl /trusted/audit-public.pem /trusted/checkpoint.json
```

Pin the public key independently. Store the signed journal and checkpoint in your organization's external retention-controlled archive. The checkpoint must be taken from a trusted, observed complete journal; a checkpoint made only after tampering cannot establish completeness. Signatures detect changed records; the chain detects missing/reordered middle records. Suffix deletion or deletion of the entire local journal is detectable only against an independently retained checkpoint/archive. A gateway administrator with the signing key can forge records. This is **not WORM storage or third-party timestamping**.

Stop the gateway for a final, consistent archival copy. The journal is capped at 100 MB and fails closed at capacity; monitor disk use, policy availability, certificate expiry and process health. Choose your own documented retention period; this standalone journal has no automatic deletion. Before capacity is reached, stop, verify, archive with an independent checkpoint, move the journal to secured archival storage and start a new journal with the same pinned key. Retain the archive ordering/checkpoints externally. Never silently truncate an active journal. For audit-key rotation, finish and archive the old journal with its old public key, then start a new journal/key and record the transition externally.

Incident response: disable forwarding, revoke the affected identity, rotate exposed provider keys and certificates, preserve the journal/checkpoints, inspect accepted-only or failed/uncertain requests against provider billing/history, and restore only after verifying the new policy and network restrictions. No automatic retry occurs after uncertain delivery.

## Compliance evidence and remaining external requirements

This package supplies access restriction, local text inspection, transport authentication, configuration-change evidence, signed metadata export and an operational runbook. The scanner is pattern-based: it does not comprehensively identify names, addresses, PHI, arbitrary source code, encoded secrets or all proprietary data. Evaluate representative data before use.

No HIPAA certification, SOC 2 report, BAA, DPA, breach-response SLA, data-residency guarantee or national regulatory approval is supplied. Your organization must establish applicable provider contracts, legal review, retention/access policies, security review and actual deployment evidence. OIDC company sign-in and SCIM provisioning are supplied by the optional enterprise package. A device agent, browser traffic interception and high-availability cluster operation are not included. These are explicit product boundaries, not completed capabilities.


## Central administration and organization governance

The management plane is part of **Prompt Guard**, not a second product. Download `governance.mjs`, `governance-console.html`, `governance-console.mjs`, `governance-console.css`, `provider-protocols.mjs`, and `verify-evidence.mjs` alongside the runtime files above. Existing installations must download `provider-protocols.mjs` when updating the gateway.

Run `node governance.mjs` as a separate administrator-controlled process. It listens on **127.0.0.1:8444** by default. The runtime continues on 8443. Use a private administrative network or authenticated tunnel; do not expose the management listener publicly or allow workload ingress to it. Configure these file-path environment variables:

| Variable | Contents / access |
|---|---|
| `GUARD_POLICY_FILE` | Shared **writable directory** containing `policy.json`. Mount that directory read-only on the data gateway. Do not use a read-only Kubernetes Secret as the editor's destination. |
| `GUARD_ADMINISTRATORS_FILE` | Root/operator-controlled administrator list; read-only to management process. |
| `GUARD_ADMIN_TLS_KEY_FILE`, `GUARD_ADMIN_TLS_CERT_FILE` | Management server identity, with the actual administrative hostname in its SAN. |
| `GUARD_ADMIN_CA_FILE` | Dedicated CA for administrative client certificates. Do not reuse the workload CA. |
| `GUARD_ADMIN_AUDIT_KEY_FILE` | A separate Ed25519 administrative audit signing key. |
| `GUARD_ADMIN_AUDIT_FILE` | Durable single-writer administrative JSONL journal. |
| `GUARD_AUDIT_FILE` | Read-only access to the runtime's request journal for export. |
| `GUARD_AUDIT_PUBLIC_KEY_FILE` | Independently pinned runtime audit public key. |
| `GUARD_ADMIN_BIND` | Optional private listener address; default is loopback. |

Generate the administrative Ed25519 keypair through your existing secret-management process. Store both public keys outside the gateway. The management service does not need provider keys, runtime audit private keys, or employee bearer tokens. Each administrator uses a separately issued clientAuth certificate/private key, installed in their browser or HTTP client. The browser console at `https://YOUR_ADMIN_HOST:8444/` uses that certificate; no password, bearer token, or third-party script is stored in the browser.

Example `administrators.json` (replace the fingerprint and expiration):

```json
[
  {"id":"security-admin","role":"admin","certificateSha256":"REPLACE_WITH_64_LOWERCASE_HEX_CHARACTERS","expiresAt":"2026-12-31T00:00:00Z"},
  {"id":"audit-reviewer","role":"auditor","certificateSha256":"REPLACE_WITH_DIFFERENT_CERTIFICATE_FINGERPRINT","expiresAt":"2026-12-31T00:00:00Z"}
]
```

`admin` can inspect and replace policy, revoke actors by removal, change scopes, and stop forwarding. `auditor` can inspect policy summaries and export evidence but cannot see policy terms/credential hashes or change policy. Only the infrastructure operator can change administrative membership/roles. The service reloads the list on every request and again after body intake. Configuration hashes and rejected authenticated management operations are journaled. Do not let administrators overwrite this membership file through the policy volume.

Policy edits require the current SHA-256 revision through `If-Match` and a new unique `version`. Concurrent edits fail with 409 and preserve the editor's draft. Unknown fields and invalid references fail closed. A durable requested-change record is written before the atomic policy replacement, followed by a committed-change record. The durable edit lock blocks gateway policy reads during publication. If a crash/storage failure occurs before the committed record, the lock remains across restart and new forwarding fails closed. A failed HTTP response can mean the new file exists but is quarantined behind this barrier. Stop every policy writer and the gateway; verify the signed administrative journal and current file hash against the requested/committed records. Restore the last committed policy, or durably record the reviewed recovery decision with both hashes in the repaired signed journal, before removing the lock and restarting. Never delete an edit lock until all writers have stopped and the policy/journal have been reconciled. Mount the whole shared policy directory into the gateway, including the edit marker; a policy-file-only mount cannot enforce this barrier. Do not edit the file concurrently with unmanaged tools.

### Organization and group policies

Optional organization-level `providers` and `models` lists restrict **every** actor. Omission preserves the existing provider/model scope. `groups` define further restrictions; an actor's optional `groups` list assigns them. The actor's provider list, organization list, and every assigned group's provider/model lists are intersected. No group can broaden an organization's rule. All custom terms are scanned locally; any matching block rule wins over redaction. Unknown groups invalidate the entire policy.

```json
{
  "version":"finance-rollout-2", "enabled":true,
  "action":"redact", "terms":["INTERNAL_PROJECT"],
  "providers":["openai","anthropic","gemini"],
  "groups":[{"id":"finance","action":"block","terms":["UNRELEASED_RESULTS"],"providers":["openai"]}],
  "actors":[]
}
```

Keep your existing certificate-bound actors in `actors` and add `"groups":["finance"]` to those needing the additional restrictions. An empty actors list denies everyone. The console's Emergency stop loads the current policy and submits a revision-checked `enabled:false` update. It blocks new forwarding when the gateway observes the file; in-flight provider requests cannot be recalled.

### Native provider text protocols

In addition to the common `/v1/chat/completions` format:

- `POST /v1/messages`: Anthropic model, system text/text blocks, user/assistant messages, `max_tokens`, optional temperature, and `stream:false`. Authenticate with the gateway token in `x-api-key` **or** a bearer header, plus the actor's client certificate.
- `POST /v1beta/models/MODEL:generateContent`: Gemini `contents` with text parts, optional text `systemInstruction`, and `generationConfig.maxOutputTokens`/`temperature`. Authenticate with the gateway token in `x-goog-api-key` **or** a bearer header, plus the actor certificate.

These routes use the same scanner, organization/group rules, revocation checks, quotas/rate bounds and audit journal. Gateway tokens are never forwarded as provider credentials. URL query credentials, streaming, images, files, tools and unsupported options are rejected. Native response conversion returns text and usage in the corresponding provider format. Disable default SDK streaming and configure client TLS; unsupported SDK options must be removed explicitly.

### Audit evidence and retention

The console exports request and administrative records separately. Every export contains the original signed chain and a signed checkpoint with sequence, head, export timestamp and SHA-256 of the exact records. Administrative events contain actor IDs, policy revisions/hashes, export events and result status; never policy terms, raw prompts or credentials. Request events include the effective policy hash and assigned group IDs.

Verify each exported bundle using pinned keys:

```sh
node verify-evidence.mjs request-export.json audit-public.pem admin-audit-public.pem previous-request-checkpoint.json
node verify-evidence.mjs admin-export.json admin-audit-public.pem admin-audit-public.pem previous-admin-checkpoint.json
```

The optional previous checkpoint is the JSON output saved from an earlier successful verification. Pin it independently to detect removal of previously observed history. Signatures without external checkpoints cannot detect rollback of a valid suffix. Archive exports in the organization's existing retention-controlled or object-lock store and verify access/retention there. No automatic deletion occurs; the existing 100 MB journal capacity fails closed, requiring planned archival/recovery. Evidence exports support operational reviews; they are not SOC 2 certification, a BAA, an independent timestamp, or proof of compliance. See enterprise-setup.md for the implemented OIDC/SCIM integration and local attachment inspection. Customer IdP configuration, device enrollment and network rollout remain customer installation steps.

## Optional enterprise identity and content package

Read [enterprise-setup.md](enterprise-setup.md) for company sign-in, SCIM employee/group provisioning, locally extracted document/image/audio inspection, runtime dependencies, deployment templates and bounded acceptance tests. The minimal image keeps text-only processing; use Enterprise.Dockerfile to enable the extractors. These are capabilities of the same Prompt Guard product.
