Skip to content

Request Notarization

QHx Notary links application requests to workload identity statements. At the signRequest level it also signs a receipt containing the captured request and response. An operator can use qhx curl to verify those artifacts while making an HTTP request.

The examples below assume an OpenAI-compatible chat service behind a QHx notary, reached through a client proxy listening on localhost:8081. Run the commands where that client proxy and the SPIFFE Workload API are available. The backend must provide the model named in the request.

You need:

  • A QHx Proxy with notarization enabled and the openai and notary-query middleware configured for the HTTP listener.
  • Client and server proxy identities that the deployment’s trust and authorization rules permit.
  • A qhx executable with access to the SPIFFE Workload API. Use --spiffe-socket-path if its socket differs from the default.
  • Network access from the CLI to the service and its /.qhx/ artifact and certificate endpoints. HTTP verification uses those endpoints and the Workload API’s trust bundles.

See qhx curl for flags and defaults. Check your installed CLI’s --version and --help when following these examples.

LevelWorkload statementRequest and response
workloadSigned and loggedNo request receipt
logRequestSigned and loggedLogged without a receipt signature
signRequestSigned and loggedLogged in a signed receipt

The workload statement identifies the workload and includes Kubernetes pod metadata, labels, annotations, and the image references declared in its pod specification. A tag in the pod specification remains a tag in this report; the report does not automatically turn it into an image digest.

For HTTP chat completions, receipts capture the method, path, body, response status, and selected headers (Content-Type and User-Agent). Choose the level according to the evidence you need and the sensitivity of the data being recorded. Request signing and storage add work; measure their impact with your own request sizes and workload.

Terminal window
qhx curl -n workload --print-workload \
-X POST -H 'Content-Type: application/json' \
-d '{"model":"llama3.2:1b","messages":[{"role":"user","content":"Hello"}]}' \
http://localhost:8081/v1/chat/completions

The CLI prints the response body to standard output. After verifying the workload statement, it prints a human-readable identity report to standard error.

Terminal window
qhx curl -n logRequest \
-X POST -H 'Content-Type: application/json' \
-d '{"model":"llama3.2:1b","messages":[{"role":"user","content":"Hello"}]}' \
http://localhost:8081/v1/chat/completions

The notary records the request and response and returns a request ID. The CLI still verifies workload identity. logRequest does not provide a signed request receipt.

Terminal window
qhx curl -n signRequest --print-receipt \
-X POST -H 'Content-Type: application/json' \
-d '{"model":"llama3.2:1b","messages":[{"role":"user","content":"Hello"}]}' \
http://localhost:8081/v1/chat/completions \
> response.json 2> receipt-report.txt

The CLI verifies the workload statement and receipt, checks their association, and compares the receipt’s captured HTTP data with the request and response. Keep validation enabled for this operation.

response.json contains the service’s response body. receipt-report.txt contains the human-readable receipt report and any diagnostics. A printed report is not a standalone signed artifact or a JSON export. qhx curl performs online verification; it does not provide an offline verification command. Long-term evidence retention also requires the signed artifacts, certificates, trusted verification material, and a verification policy.

The response headers identify the artifacts using base64url-encoded values:

Qhx-Workload-Id: <base64url workload statement ID>
Qhx-Request-Id: <base64url request ID>

The request ID is present for logRequest and signRequest. Use the values returned by the service when looking up artifacts; the placeholders above are not IDs to send to a server.

The following is a QHx Proxy configuration template for an HTTP central notary. Replace the target URL and both identity patterns with the addresses and identities authorized by your deployment. Mount the SPIFFE Workload API socket and writable storage at the configured paths.

spiffe:
workload_socket_path: unix:///spiffe-workload-api/agent.sock
notary:
enable: true
database:
path: /var/lib/qhx-notary/notary.db
listeners:
- name: central-http
address: 0.0.0.0:8081
protocol: http
mode: central
source:
spiffe_ids:
- '^spiffe://client\.example/ns/ai-chat/sa/llm-client/.*$'
target:
url: https://app-server.ai-chat.svc.cluster.local:8081
spiffe_ids:
- '^spiffe://server\.example/ns/ai-chat/sa/ollama-server/.*$'
middlewares:
- type: notary-query
- type: openai

Supply the YAML through the proxy’s QHX_PROXY_CONFIG environment variable or its -config file option. The openai middleware handles POST /v1/chat/completions; other endpoints are rejected by default. The notary also needs Kubernetes permission to read the pod metadata used in workload statements. The configuration alone does not create storage, RBAC, proxy sidecars, or application routes.

Use persistent storage if artifacts must survive pod replacement. Protect notary data and backups according to the sensitivity of request and response bodies. Configure retention through your storage and operational process; a writable database path does not make storage immutable or guarantee retention.

A valid signature links the notary’s statement to its signing identity and protects the signed contents against modification. It does not prove that an AI response is correct or independently attest model weights, training data, or every event in an application’s history. Decide which claims satisfy your own audit requirements and retain their verification material accordingly.

If HTTP validation fails, check that the request reached the configured notary, that the CLI can access the Workload API and /.qhx/ endpoints, and that their trust material matches the intended deployment. --validate=false permits a missing workload statement; it is not a remedy for failed verification of a QHx-protected service.

For MQTT, the CLI only decodes and displays live notary messages without verifying signatures. See MQTT artifact inspection before using that output as evidence.