Skip to content

Example — protect an agent end-to-end

This is a full worked example: take a customer-support chatbot from “no controls” to a namespace where every tool call is enforced. Every manifest here also ships in the repo under crds/examples/.

An NrvqClass documents what kind of agent this is — its intended tool surface and trust defaults. It seeds the policy/intent generators; it does not enforce on its own.

class-customer-support.yaml
apiVersion: norviq.io/v1alpha1
kind: NrvqClass
metadata:
name: customer-support
spec:
description: Customer-facing chatbot agents for orders, refunds, and product help
allowedTools: [search_kb, get_customer, get_order, update_order_status, send_email]
blockedTools: [execute_sql, delete_record, spawn_pod, exec_shell]
maxCallsPerMinute: 60
initialTrustScore: 0.8
trustThreshold: 0.4
Terminal window
kubectl apply -f class-customer-support.yaml

An NrvqPolicy supplies the actual decision. Start with a strict preset in block mode, targeting the class:

policy-strict-chatbot.yaml
apiVersion: norviq.io/v1alpha1
kind: NrvqPolicy
metadata:
name: chatbot-strict
namespace: chatbot-prod
spec:
target:
agentClass: customer-support
enforcementMode: block
preset: strict # strict | moderate | permissive — or supply custom `rego`
priority: 200

Add a namespace baseline as a floor for everything in the namespace, regardless of class. Running it in audit first lets you watch before you block:

policy-namespace-baseline.yaml
apiVersion: norviq.io/v1alpha1
kind: NrvqPolicy
metadata:
name: prod-baseline
namespace: chatbot-prod
spec:
target:
namespace: chatbot-prod # applies to every agent in the namespace
enforcementMode: audit
preset: permissive
priority: 50
Terminal window
kubectl apply -f policy-strict-chatbot.yaml
kubectl apply -f policy-namespace-baseline.yaml
# confirm the controller synced them to the engine
kubectl get nrvqpolicy -n chatbot-prod

Resolution is by numeric priority — the highest-priority policy wins, with the most-restrictive decision breaking ties. Here the class policy (200) outranks the namespace baseline (50) because those priorities encode that intent; a namespace policy with a higher number would win instead. See Concepts → Policy tiers.

3. Deploy the agent and turn on enforcement

Section titled “3. Deploy the agent and turn on enforcement”

Label the namespace so the mutating webhook injects the enforcement sidecar into every pod, then tell each agent pod which class it is:

Terminal window
kubectl label namespace chatbot-prod norviq-injection=enabled
agent-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: support-agent
namespace: chatbot-prod
spec:
template:
metadata:
labels:
norviq.io/agent-class: customer-support # binds this pod to the class above
spec:
containers:
- name: agent
image: your-org/support-agent:latest
Terminal window
kubectl apply -f agent-deployment.yaml
# the sidecar is injected automatically; no image change to your agent

An allowed tool call passes; a destructive one is blocked before it runs:

Terminal window
# a normal call — allowed
norviq audit list -n chatbot-prod -d allow --range 1h
# prove a block: run the built-in red team against the class
norviq redteam run --namespace chatbot-prod --agent customer-support

You should see the suite’s execute_sql / exec_shell attempts land as block in the audit log, while its benign search_kb probe is allowed. Watch it live in the console’s audit stream, or graph the agent’s real reach under Asset Graph / Attack Graph — see Asset & attack graphs for the full discovery-and-defense loop.