From 60d9a70aff72bddcb76bf680f4b189ea7964ef93 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 19 Jun 2026 11:16:38 -0400 Subject: [PATCH] Refresh Pipelock integration for v2.8 receipts (#2406) * chore(pipelock): refresh integration for v2.8 receipts * Clarify Pipelock receipt key mounts --- .github/workflows/pipelock.yml | 3 +- charts/sure/CHANGELOG.md | 11 ++ charts/sure/README.md | 71 ++++++++++-- charts/sure/templates/_helpers.tpl | 2 +- charts/sure/templates/pipelock-configmap.yaml | 30 ++++- .../sure/templates/pipelock-deployment.yaml | 6 + charts/sure/values.yaml | 16 ++- compose.example.ai.yml | 23 +++- docs/hosting/ai.md | 6 +- docs/hosting/docker.md | 1 + docs/hosting/mcp.md | 1 + docs/hosting/pipelock.md | 103 +++++++++++++++++- pipelock.example.yaml | 30 +++-- 13 files changed, 274 insertions(+), 29 deletions(-) diff --git a/.github/workflows/pipelock.yml b/.github/workflows/pipelock.yml index f19d3b94f..a5249d9ed 100644 --- a/.github/workflows/pipelock.yml +++ b/.github/workflows/pipelock.yml @@ -17,8 +17,9 @@ jobs: persist-credentials: false - name: Pipelock Scan - uses: luckyPipewrench/pipelock@cef4f47eb99ffe00e20fa7d1423bff1a44742dbe # v2.4.0 + uses: luckyPipewrench/pipelock@818ca0a7af4dbcd56ada7fa57e2dc32f9e799e34 # v2.8.0 with: + version: '2.8.0' scan-diff: 'true' fail-on-findings: 'true' test-vectors: 'false' diff --git a/charts/sure/CHANGELOG.md b/charts/sure/CHANGELOG.md index 490cbe136..7b3afe88b 100644 --- a/charts/sure/CHANGELOG.md +++ b/charts/sure/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to the Sure Helm chart will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed +- Bumped `pipelock.image.tag` from `2.5.0` to `2.8.0`, picking up default-on flight recorder receipts, safe-by-default receipt verification, MCP `defer` authorization, `pipelock explain`, `pipelock keys status`, `pipelock support bundle`, verified self-update, and inert-exemption diagnostics. +- Refreshed Pipelock docs across Docker, MCP, AI, and chart setup to distinguish scanning from verifiable receipt evidence. +- Enabled `pipelock.requestBodyScanning` by default with `action: warn`, matching Pipelock's current balanced preset so outbound prompt bodies and sensitive headers are scanned. + +### Added +- `pipelock.flightRecorder`: structured Helm values for rendering `flight_recorder.enabled`, `require_receipts`, `redact`, `dir`, and `signing_key_path`. +- `pipelock.extraVolumes` and `pipelock.extraVolumeMounts`: mount receipt evidence storage and receipt-signing keys without duplicating the Pipelock deployment template. + ## [0.7.1] - 2026-05-31] ### Changed diff --git a/charts/sure/README.md b/charts/sure/README.md index 42a6688c8..a7581cc99 100644 --- a/charts/sure/README.md +++ b/charts/sure/README.md @@ -645,7 +645,7 @@ hpa: - **Forward proxy** (port 8888): Scans outbound HTTPS from Faraday-based AI clients. Auto-injected via `HTTPS_PROXY` env vars when enabled. - **MCP reverse proxy** (port 8889): Scans inbound MCP traffic from external AI assistants. -Recent pipelock releases add the Audit Packet v0 schema and language-portable verifiers (Go, TypeScript, Rust), request-body prompt-injection blocking, SPIFFE-strict inbound mediation envelopes, scanner attribution on MCP block receipts, enhanced tool poisoning detection, per-read kill switch preemption, trusted domain allowlisting, MCP tool redirect profiles, signed action receipts, per-pattern DLP warn mode, learn-and-lock behavioural contracts, the wedge-detection health watchdog, and the `pipelock posture verify` / `pipelock session` / `pipelock doctor` CLIs. Browser Shield, process sandboxing, and attack simulation are available via `extraConfig` and CLI. See the [pipelock changelog](https://github.com/luckyPipewrench/pipelock/releases) for details. +Recent Pipelock releases add default-on flight recorder receipts, safe-by-default receipt verification, MCP `defer` authorization, request-policy scoring, request-body prompt-injection blocking, SPIFFE-strict inbound mediation envelopes, scanner attribution on MCP block receipts, trusted domain allowlisting, MCP tool redirect profiles, learn-and-lock behavioural contracts, the wedge-detection health watchdog, `pipelock explain`, `pipelock keys status`, `pipelock support bundle`, verified `pipelock update`, and `pipelock doctor` checks for inert exemptions. Browser Shield, process sandboxing, request policy, redaction, and attack assessment are available via `extraConfig` and CLI. See the [Pipelock changelog](https://github.com/luckyPipewrench/pipelock/releases) for details. ### Enabling Pipelock @@ -653,7 +653,7 @@ Recent pipelock releases add the Audit Packet v0 schema and language-portable ve pipelock: enabled: true image: - tag: "2.5.0" + tag: "2.8.0" mode: balanced # strict, balanced, or audit ``` @@ -702,7 +702,7 @@ pipelock: headerMode: sensitive # "sensitive" or "all" ``` -Disabled by default. Roll out with `action: warn` first to observe findings in logs without blocking, then flip to `action: block` once the false-positive rate is acceptable. +Enabled by default with `action: warn`, matching Pipelock's balanced preset. Review findings in logs before flipping to `action: block`. ### Health watchdog @@ -716,19 +716,72 @@ pipelock: exposeSubsystems: true # adds per-subsystem boolean map to /health ``` -### Validating your config +### Signed action receipts -Pipelock includes CLI tools for config validation: +The flight recorder writes hash-chained, Ed25519-signed action receipts. The chart renders the `flight_recorder` config, but recording is inert until you mount a writable evidence directory and the signing key named by `signingKeyPath`. + +Generate the receipt key once: ```bash -# Run 24 synthetic attack scenarios against your config -pipelock simulate --config pipelock.yaml +# --out must be an absolute path; "$PWD/..." writes the key into the current directory. +pipelock signing key generate --purpose receipt-signing --out "$PWD/flight-recorder-signing.key" --id sure-k8s +kubectl create secret generic sure-pipelock-receipts \ + --namespace sure \ + --from-file=flight-recorder-signing.key=./flight-recorder-signing.key +``` + +If you do not have the `pipelock` binary installed, generate the key with the image instead: `docker run --rm -v "$PWD:/out" ghcr.io/luckypipewrench/pipelock:2.8.0 signing key generate --purpose receipt-signing --out /out/flight-recorder-signing.key --id sure-k8s`. + +Then mount persistent evidence storage and the key: + +```yaml +pipelock: + flightRecorder: + enabled: true + dir: /var/lib/pipelock/evidence + signingKeyPath: /run/secrets/pipelock/flight-recorder-signing.key + requireReceipts: false + redact: true + extraVolumes: + - name: pipelock-evidence + persistentVolumeClaim: + claimName: sure-pipelock-evidence + - name: pipelock-receipt-key + secret: + secretName: sure-pipelock-receipts + # 0440 (group-read), not 0400: the chart runs Pipelock as uid 1000 with + # fsGroup 1000, so the secret file is owned root:1000. A 0400 file would + # be unreadable by the non-root process and Pipelock would crash on + # startup with a key-load error. 0440 lets the fsGroup read it. + defaultMode: 0440 + extraVolumeMounts: + - name: pipelock-evidence + mountPath: /var/lib/pipelock/evidence + - name: pipelock-receipt-key + # Do not mount this under /etc/pipelock; the chart already mounts the + # Pipelock ConfigMap there. + mountPath: /run/secrets/pipelock + readOnly: true +``` + +Only set `requireReceipts: true` after confirming receipts are being written. With it enabled, allow-path traffic fails closed if Pipelock cannot sign or persist the receipt. + +### Validating your config + +Pipelock includes CLI tools for config validation and deployment diagnostics: + +```bash +# Create and run a broader assessment workspace +pipelock assess init --config pipelock.yaml # Score your config's security posture (0-100) pipelock audit score --config pipelock.yaml # Report whether configured protections are actually enforceable pipelock doctor + +# Explain a block and the exact config knob that scanner reads +pipelock explain --config pipelock.yaml "https://example.com/path" ``` ### Exposing MCP to external AI assistants @@ -795,7 +848,7 @@ pipelock: ### Extra config (escape hatch) -For Pipelock config sections not covered by structured values (session profiling, data budgets, kill switch, sandbox, reverse proxy, adaptive enforcement, etc.), use `extraConfig`: +For Pipelock config sections not covered by structured values (session profiling, data budgets, kill switch, sandbox, reverse proxy, adaptive enforcement, request policy, redaction, etc.), use `extraConfig`: ```yaml pipelock: @@ -847,7 +900,7 @@ See `values.yaml` for the complete configuration surface, including: - `migrations.*`: strategy job or initContainer - `simplefin.encryption.*`: enable + backfill options - `cronjobs.*`: custom CronJobs -- `pipelock.*`: AI agent security proxy (forward proxy, MCP reverse proxy, DLP, injection scanning, request-body scanning, health watchdog, trusted domains, tool redirect profiles, logging, serviceMonitor, ingress, PDB, extraConfig) +- `pipelock.*`: AI agent security proxy (forward proxy, MCP reverse proxy, DLP, injection scanning, request-body scanning, health watchdog, signed receipts, trusted domains, tool redirect profiles, logging, serviceMonitor, ingress, PDB, extraVolumes, extraVolumeMounts, extraConfig) - `service.*`, `ingress.*`, `serviceMonitor.*`, `hpa.*` ## Helm tests diff --git a/charts/sure/templates/_helpers.tpl b/charts/sure/templates/_helpers.tpl index d36105db9..539401d5e 100644 --- a/charts/sure/templates/_helpers.tpl +++ b/charts/sure/templates/_helpers.tpl @@ -161,7 +161,7 @@ true {{/* Pipelock image string */}} {{- define "sure.pipelockImage" -}} {{- $repo := "ghcr.io/luckypipewrench/pipelock" -}} -{{- $tag := "latest" -}} +{{- $tag := "2.8.0" -}} {{- if .Values.pipelock.image -}} {{- $repo = .Values.pipelock.image.repository | default $repo -}} {{- $tag = .Values.pipelock.image.tag | default $tag -}} diff --git a/charts/sure/templates/pipelock-configmap.yaml b/charts/sure/templates/pipelock-configmap.yaml index c77ee68ba..e49c27004 100644 --- a/charts/sure/templates/pipelock-configmap.yaml +++ b/charts/sure/templates/pipelock-configmap.yaml @@ -65,7 +65,7 @@ {{- $chainWindow = int (.Values.pipelock.toolChainDetection.windowSize | default 20) -}} {{- $chainGap = int (.Values.pipelock.toolChainDetection.maxGap | default 3) -}} {{- end -}} -{{- $rbsEnabled := false -}} +{{- $rbsEnabled := true -}} {{- $rbsAction := "warn" -}} {{- $rbsMaxBytes := 5242880 -}} {{- $rbsScanHeaders := true -}} @@ -93,6 +93,24 @@ {{- $hwExpose = .Values.pipelock.healthWatchdog.exposeSubsystems -}} {{- end -}} {{- end -}} +{{- $frEnabled := true -}} +{{- $frRequireReceipts := false -}} +{{- $frRedact := true -}} +{{- $frDir := "" -}} +{{- $frSigningKeyPath := "" -}} +{{- if .Values.pipelock.flightRecorder -}} +{{- if hasKey .Values.pipelock.flightRecorder "enabled" -}} +{{- $frEnabled = .Values.pipelock.flightRecorder.enabled -}} +{{- end -}} +{{- if hasKey .Values.pipelock.flightRecorder "requireReceipts" -}} +{{- $frRequireReceipts = .Values.pipelock.flightRecorder.requireReceipts -}} +{{- end -}} +{{- if hasKey .Values.pipelock.flightRecorder "redact" -}} +{{- $frRedact = .Values.pipelock.flightRecorder.redact -}} +{{- end -}} +{{- $frDir = .Values.pipelock.flightRecorder.dir | default "" -}} +{{- $frSigningKeyPath = .Values.pipelock.flightRecorder.signingKeyPath | default "" -}} +{{- end -}} {{- $logFormat := "json" -}} {{- $logOutput := "stdout" -}} {{- $logIncludeAllowed := false -}} @@ -197,6 +215,16 @@ data: enabled: {{ $hwEnabled }} interval_seconds: {{ $hwInterval }} expose_subsystems: {{ $hwExpose }} + flight_recorder: + enabled: {{ $frEnabled }} + require_receipts: {{ $frRequireReceipts }} + redact: {{ $frRedact }} +{{- if $frDir }} + dir: {{ $frDir | quote }} +{{- end }} +{{- if $frSigningKeyPath }} + signing_key_path: {{ $frSigningKeyPath | quote }} +{{- end }} logging: format: {{ $logFormat }} output: {{ $logOutput }} diff --git a/charts/sure/templates/pipelock-deployment.yaml b/charts/sure/templates/pipelock-deployment.yaml index bf57ec8ab..f1b1ea223 100644 --- a/charts/sure/templates/pipelock-deployment.yaml +++ b/charts/sure/templates/pipelock-deployment.yaml @@ -45,6 +45,9 @@ spec: - name: config configMap: name: {{ include "sure.fullname" . }}-pipelock + {{- with .Values.pipelock.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} containers: - name: pipelock image: {{ include "sure.pipelockImage" . }} @@ -63,6 +66,9 @@ spec: - name: config mountPath: /etc/pipelock readOnly: true + {{- with .Values.pipelock.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} ports: - name: proxy containerPort: {{ $fwdPort }} diff --git a/charts/sure/values.yaml b/charts/sure/values.yaml index d01d0dc5e..193fa2b69 100644 --- a/charts/sure/values.yaml +++ b/charts/sure/values.yaml @@ -497,7 +497,7 @@ pipelock: enabled: false image: repository: ghcr.io/luckypipewrench/pipelock - tag: "2.5.0" + tag: "2.8.0" pullPolicy: IfNotPresent imagePullSecrets: [] replicas: 1 @@ -565,7 +565,7 @@ pipelock: # destinations even when action is "warn"; trusted provider hosts (OpenAI, # Anthropic, etc.) remain exempt via the response_scanning exemption list. requestBodyScanning: - enabled: false + enabled: true action: warn # warn or block maxBodyBytes: 5242880 # 5 MB; fail-closed above this scanHeaders: true # scan request headers for DLP @@ -577,6 +577,16 @@ pipelock: enabled: true intervalSeconds: 2 exposeSubsystems: false # include per-subsystem map in /health response + # Flight recorder: signed, hash-chained action receipts. Enabled by default in + # Pipelock, but inert until both dir and signingKeyPath are set and mounted. + # Use extraVolumes/extraVolumeMounts below to mount persistent storage and a + # Secret containing the signing key. + flightRecorder: + enabled: true + requireReceipts: false # true = fail closed if allow-path receipt cannot be emitted + redact: true # redact DLP-shaped content before writing receipts + dir: "" # e.g. /var/lib/pipelock/evidence + signingKeyPath: "" # e.g. /run/secrets/pipelock/flight-recorder-signing.key service: type: ClusterIP resources: @@ -590,6 +600,8 @@ pipelock: tolerations: [] affinity: {} topologySpreadConstraints: [] + extraVolumes: [] + extraVolumeMounts: [] # Prometheus Operator ServiceMonitor for /metrics on the proxy port serviceMonitor: diff --git a/compose.example.ai.yml b/compose.example.ai.yml index 48a696f38..c09fe1b39 100644 --- a/compose.example.ai.yml +++ b/compose.example.ai.yml @@ -112,12 +112,33 @@ x-rails-env: &rails_env services: pipelock: - image: ghcr.io/luckypipewrench/pipelock:latest # pin to a specific version (e.g., :2.5.0) for production + image: ghcr.io/luckypipewrench/pipelock:2.8.0 + user: "${PIPELOCK_UID:-1000}:${PIPELOCK_GID:-1000}" container_name: pipelock hostname: pipelock restart: unless-stopped volumes: - ./pipelock.example.yaml:/etc/pipelock/pipelock.yaml:ro + # Optional signed receipts (flight recorder). Off until you create the + # dirs, generate a key, uncomment the two mounts below, and uncomment + # flight_recorder.dir + signing_key_path in pipelock.example.yaml. + # Create the dirs yourself first so they are owned by your host user + # (Docker would otherwise create missing bind-mount paths as root, which + # the uid-1000 Pipelock process cannot write to): + # mkdir -p ./pipelock-evidence ./pipelock-keys + # Generate the receipt-signing key via the image (no host binary needed; + # --out must be an absolute path inside the container): + # docker run --rm -v "$PWD/pipelock-keys:/keys" ghcr.io/luckypipewrench/pipelock:2.8.0 \ + # signing key generate --purpose receipt-signing --out /keys/flight-recorder-signing.key --id sure-compose + # The key is written 0600 owned by uid 1000 (Pipelock's default user). If + # your host user is not uid 1000, use this variant instead: + # export PIPELOCK_UID="$(id -u)" PIPELOCK_GID="$(id -g)" + # docker run --rm --user "$PIPELOCK_UID:$PIPELOCK_GID" -v "$PWD/pipelock-keys:/keys" ghcr.io/luckypipewrench/pipelock:2.8.0 \ + # signing key generate --purpose receipt-signing --out /keys/flight-recorder-signing.key --id sure-compose + # That makes the key and evidence directory readable/writable by the same + # uid/gid the compose service uses. + # - ./pipelock-evidence:/var/lib/pipelock/evidence + # - ./pipelock-keys:/etc/pipelock/keys:ro command: - "run" - "--config" diff --git a/docs/hosting/ai.md b/docs/hosting/ai.md index 70c89d557..92e17bb48 100644 --- a/docs/hosting/ai.md +++ b/docs/hosting/ai.md @@ -448,6 +448,8 @@ When [Pipelock](https://github.com/luckyPipewrench/pipelock) is enabled (`pipelo Pipelock scans for prompt injection, DLP violations, and tool poisoning. The external agent does not need Pipelock installed. Sure's Pipelock handles both directions. +If you need audit evidence, configure Pipelock's flight recorder as described in [Pipelock signed action receipts](pipelock.md#signed-action-receipts). `pipelock.enabled=true` gives scanning; receipts require mounted evidence storage plus a receipt-signing key. + **`NO_PROXY` behavior (Helm/Kubernetes only):** The Helm chart's env template sets `NO_PROXY` to include `.svc.cluster.local` and other internal domains. This means in-cluster agent URLs (like `http://agent.namespace.svc.cluster.local:18789`) bypass the forward proxy and go directly. If your agent is in-cluster, its traffic won't be forward-proxy scanned (but MCP callbacks from the agent are still scanned by the reverse proxy). Docker Compose deployments use a different `NO_PROXY` set; check your compose file for the exact values. **`mcpToolPolicy` note:** The Helm chart's `pipelock.mcpToolPolicy.enabled` defaults to `false`. Pipelock rejects an enabled tool policy with no rules, so the chart ships it off by default. To turn it on, define at least one rule and set `enabled: true`: @@ -1078,9 +1080,9 @@ ollama pull model-name # Install a model kubectl logs deploy/sure-worker -c sidekiq --tail=50 | grep -i "external\|assistant\|error" ``` -4. **If using Pipelock:** Check pipelock sidecar logs. A crashed pipelock can block outbound requests: +4. **If using Pipelock:** Check the Pipelock deployment logs. A crashed Pipelock proxy can block outbound requests: ```bash - kubectl logs deploy/sure-worker -c pipelock --tail=20 + kubectl logs deploy/sure-pipelock --tail=20 ``` ### High Costs diff --git a/docs/hosting/docker.md b/docs/hosting/docker.md index afd462752..575ef7db5 100644 --- a/docs/hosting/docker.md +++ b/docs/hosting/docker.md @@ -251,6 +251,7 @@ Pipelock sits between Sure and external services, scanning AI traffic for: - **Secret exfiltration** (DLP): catches API keys, tokens, or personal data leaking in prompts - **Prompt injection**: detects attempts to override system instructions - **Tool poisoning**: validates MCP tool calls against known-safe patterns +- **Signed receipts**: optional hash-chained evidence of mediated decisions when `flight_recorder.dir` and `signing_key_path` are configured When using `compose.example.ai.yml`, Pipelock is always running. External AI agents should connect to port 8889 (MCP reverse proxy) instead of directly to Sure's `/mcp` on port 3000. diff --git a/docs/hosting/mcp.md b/docs/hosting/mcp.md index db019163f..39b60bd8e 100644 --- a/docs/hosting/mcp.md +++ b/docs/hosting/mcp.md @@ -230,6 +230,7 @@ Pipelock provides: - **Prompt injection detection**: Identifies attempts to manipulate the AI - **Tool poisoning detection**: Prevents malicious tool call sequences - **Policy enforcement**: Block or warn on suspicious patterns +- **Signed receipts**: Produces verifiable evidence for mediated MCP decisions when the flight recorder is configured with storage and a signing key See the [Pipelock documentation](pipelock.md) and the example configuration in `compose.example.ai.yml` for setup instructions. diff --git a/docs/hosting/pipelock.md b/docs/hosting/pipelock.md index 0cd5ed126..09980d08d 100644 --- a/docs/hosting/pipelock.md +++ b/docs/hosting/pipelock.md @@ -48,6 +48,38 @@ The `compose.example.ai.yml` file includes Pipelock. To use it: # Should show "healthy" ``` +4. Optional: enable signed action receipts. + + Pipelock's flight recorder is on by default, but it writes nothing until it has a writable evidence directory and a receipt-signing key. Create the directories yourself first (so they are owned by your host user, not root), then generate the key with the Pipelock image so you do not need the binary installed locally: + + ```bash + mkdir -p pipelock-evidence pipelock-keys + # --out must be an absolute path inside the container. The key is written + # 0600 owned by uid 1000, which is the user the Pipelock proxy runs as. + docker run --rm -v "$PWD/pipelock-keys:/keys" ghcr.io/luckypipewrench/pipelock:2.8.0 \ + signing key generate --purpose receipt-signing --out /keys/flight-recorder-signing.key --id sure-compose + ``` + + If your host user is not uid 1000, use this variant instead so the mounted key and evidence directory are readable and writable by the same user that runs the Pipelock service. `compose.example.ai.yml` already has `user: "${PIPELOCK_UID:-1000}:${PIPELOCK_GID:-1000}"` on the `pipelock` service, so export those variables in the same shell before restarting, or put them in your `.env` file: + + ```bash + export PIPELOCK_UID="$(id -u)" PIPELOCK_GID="$(id -g)" + docker run --rm --user "$PIPELOCK_UID:$PIPELOCK_GID" -v "$PWD/pipelock-keys:/keys" ghcr.io/luckypipewrench/pipelock:2.8.0 \ + signing key generate --purpose receipt-signing --out /keys/flight-recorder-signing.key --id sure-compose + ``` + + Then uncomment the `pipelock-evidence` and `pipelock-keys` volume mounts in `compose.example.ai.yml`, uncomment `flight_recorder.dir` and `flight_recorder.signing_key_path` in `pipelock.example.yaml`, and restart Pipelock from the same shell if you exported `PIPELOCK_UID` and `PIPELOCK_GID`: + + ```bash + docker compose -f compose.ai.yml restart pipelock + ``` + + Print the public verifier key when you need to hand receipts to another system: + + ```bash + docker compose -f compose.ai.yml exec pipelock /pipelock signing pubkey --config /etc/pipelock/pipelock.yaml + ``` + ### Connecting external AI agents External agents should use the MCP reverse proxy port: @@ -77,13 +109,65 @@ Enable Pipelock in your Helm values: pipelock: enabled: true image: - tag: "2.5.0" + tag: "2.8.0" mode: balanced ``` This creates a separate Deployment, Service, and ConfigMap. The chart auto-injects `HTTPS_PROXY`/`HTTP_PROXY`/`NO_PROXY` into web and worker pods. -Recent pipelock releases add the Audit Packet v0 schema and language-portable verifiers (Go/TypeScript/Rust), request-body prompt-injection blocking, SPIFFE-strict inbound mediation envelopes, scanner attribution on MCP block receipts, trusted domain allowlisting, MCP tool redirect profiles, enhanced tool poisoning detection, per-read kill switch preemption, signed action receipts, per-pattern DLP warn mode, learn-and-lock behavioural contracts, the wedge-detection health watchdog, and the `pipelock posture verify` / `pipelock session` / `pipelock doctor` CLI commands. See the [pipelock changelog](https://github.com/luckyPipewrench/pipelock/releases) for details. +Recent Pipelock releases add default-on flight recorder receipts, safe-by-default receipt verification, MCP `defer` authorization, request-policy scoring, request-body prompt-injection blocking, SPIFFE-strict inbound mediation envelopes, scanner attribution on MCP block receipts, trusted domain allowlisting, MCP tool redirect profiles, learn-and-lock behavioural contracts, the wedge-detection health watchdog, `pipelock explain`, `pipelock keys status`, `pipelock support bundle`, verified `pipelock update`, and `pipelock doctor` checks for inert exemptions. See the [Pipelock changelog](https://github.com/luckyPipewrench/pipelock/releases) for details. + +### Signed action receipts + +Pipelock can write hash-chained, Ed25519-signed receipts for proxied decisions. This is the audit trail that proves what crossed the Pipelock boundary and what policy verdict was applied. + +The chart exposes `pipelock.flightRecorder`, but recording is inert until you mount both storage and a signing key: + +```bash +# --out must be an absolute path; "$PWD/..." writes the key into the current directory. +pipelock signing key generate --purpose receipt-signing --out "$PWD/flight-recorder-signing.key" --id sure-k8s +kubectl create namespace sure +kubectl create secret generic sure-pipelock-receipts \ + --namespace sure \ + --from-file=flight-recorder-signing.key=./flight-recorder-signing.key +``` + +If you do not have the `pipelock` binary installed, generate the key with the image instead: `docker run --rm -v "$PWD:/out" ghcr.io/luckypipewrench/pipelock:2.8.0 signing key generate --purpose receipt-signing --out /out/flight-recorder-signing.key --id sure-k8s`. + +Example Helm values using an existing PVC named `sure-pipelock-evidence`: + +```yaml +pipelock: + enabled: true + flightRecorder: + enabled: true + dir: /var/lib/pipelock/evidence + signingKeyPath: /run/secrets/pipelock/flight-recorder-signing.key + requireReceipts: false + redact: true + extraVolumes: + - name: pipelock-evidence + persistentVolumeClaim: + claimName: sure-pipelock-evidence + - name: pipelock-receipt-key + secret: + secretName: sure-pipelock-receipts + # 0440 (group-read), not 0400: the chart runs Pipelock as uid 1000 with + # fsGroup 1000, so the secret file is owned root:1000. A 0400 file would + # be unreadable by the non-root process and Pipelock would crash on + # startup with a key-load error. 0440 lets the fsGroup read it. + defaultMode: 0440 + extraVolumeMounts: + - name: pipelock-evidence + mountPath: /var/lib/pipelock/evidence + - name: pipelock-receipt-key + # Do not mount this under /etc/pipelock; the chart already mounts the + # Pipelock ConfigMap there. + mountPath: /run/secrets/pipelock + readOnly: true +``` + +Keep `requireReceipts: false` until you have confirmed receipts are being written. Turning it on makes allow-path receipt emission fail closed: if Pipelock cannot sign or write the receipt, the request is blocked before egress. ### Exposing MCP to external agents (Kubernetes) @@ -158,9 +242,10 @@ The `pipelock.example.yaml` file (Docker Compose) or ConfigMap (Helm) controls s | `tool_chain_detection` | Multi-step attack patterns | | `websocket_proxy` | WebSocket frame scanning (disabled by default) | | `health_watchdog` | Wedge-detection on subsystem heartbeats, returns 503 on stall (pipelock 2.4+) | +| `flight_recorder` | Signed action receipts and hash-chained evidence (inert until storage + signing key are mounted) | | `logging` | Output format (json/text), verbosity | -For the Helm chart, most sections are configurable via `values.yaml`. For additional sections not covered by structured values (session profiling, data budgets, kill switch, sandbox, reverse proxy, adaptive enforcement), use the `extraConfig` escape hatch: +For the Helm chart, most sections are configurable via `values.yaml`. For additional sections not covered by structured values (session profiling, data budgets, kill switch, sandbox, reverse proxy, adaptive enforcement, request policy, redaction), use the `extraConfig` escape hatch: ```yaml pipelock: @@ -185,6 +270,7 @@ Start with `audit` mode to see what Pipelock detects without blocking anything. - Forward proxy only covers Faraday-based HTTP clients. Net::HTTP, HTTParty, and other libraries ignore `HTTPS_PROXY`. - Docker Compose has no egress network policies. The `/mcp` endpoint on port 3000 is still reachable directly (auth token required). For enforcement, use Kubernetes NetworkPolicies. - Pipelock scans text content. Binary payloads (images, file uploads) are passed through by default. +- Signed receipts prove traffic that traversed Pipelock. They do not prove traffic could not bypass Pipelock; pair them with NetworkPolicies, containment, or firewall rules for non-bypass claims. ## Troubleshooting @@ -222,3 +308,14 @@ docker compose -f compose.ai.yml exec pipelock /pipelock healthcheck --addr 127. ``` Check that `MCP_API_TOKEN` and `MCP_USER_EMAIL` are set in your `.env` file and that the email matches an existing Sure user. + +### Receipts are not being written + +Run: + +```bash +docker compose -f compose.ai.yml exec pipelock /pipelock keys status --config /etc/pipelock/pipelock.yaml +docker compose -f compose.ai.yml exec pipelock /pipelock doctor --config /etc/pipelock/pipelock.yaml +``` + +The `receipt-signing` key must be present, readable by the Pipelock process, and valid. The `flight_recorder.dir` path must be writable. diff --git a/pipelock.example.yaml b/pipelock.example.yaml index 4e2af49f9..8f709e3de 100644 --- a/pipelock.example.yaml +++ b/pipelock.example.yaml @@ -1,14 +1,15 @@ # Pipelock configuration for Docker Compose # See https://github.com/luckyPipewrench/pipelock for full options. # -# Recent additions (2.5): Audit Packet v0 schema with Go/TypeScript/Rust -# verifiers, request-body prompt-injection blocking, SPIFFE-strict inbound -# mediation envelopes, scanner attribution on MCP block receipts, wedge- -# detection health watchdog, learn-and-lock behavioural contracts, trusted -# domains, redirect profiles, attack simulation, security scoring, process -# sandbox, signed action receipts, per-pattern DLP warn mode, and the -# `pipelock posture verify` / `pipelock session` / `pipelock doctor` CLIs. -# Run `pipelock simulate --config ` to test your config against 24 attack scenarios. +# Recent additions through 2.8: default-on flight recorder receipts, safe-by- +# default receipt verification, request-policy scoring, request-body prompt- +# injection blocking, SPIFFE-strict inbound mediation envelopes, scanner +# attribution on MCP block receipts, wedge-detection health watchdog, +# learn-and-lock behavioural contracts, trusted domains, redirect profiles, +# MCP `defer` authorization, `pipelock explain`, `pipelock keys status`, +# `pipelock support bundle`, verified `pipelock update`, and `pipelock doctor` +# checks for inert exemptions. +# Run `pipelock assess init --config ` to create an assessment workspace. # Run `pipelock audit score --config ` for a security posture score (0-100). # Run `pipelock doctor` to verify configured protections are actually enforceable. @@ -83,7 +84,7 @@ tool_chain_detection: # destinations even when action is "warn". Trusted provider hosts (OpenAI, # Anthropic, etc.) remain exempt via the response_scanning exemption list. request_body_scanning: - enabled: false + enabled: true action: warn max_body_bytes: 5242880 scan_headers: true @@ -96,3 +97,14 @@ health_watchdog: enabled: true interval_seconds: 2 expose_subsystems: false + +# Flight recorder (pipelock 2.7+): signed, hash-chained action receipts. +# Enabled by default, but inert until both `dir` and `signing_key_path` are set. +# For Docker Compose, mount ./pipelock-evidence and ./pipelock-keys as shown in +# compose.example.ai.yml, then uncomment these paths. +flight_recorder: + enabled: true + require_receipts: false + redact: true + # dir: /var/lib/pipelock/evidence + # signing_key_path: /etc/pipelock/keys/flight-recorder-signing.key