Configure Tool Policies
This guide covers common operational tasks for configuring ToolPolicy resources. For the full field reference, see the ToolPolicy CRD Reference.
Prerequisites
Section titled “Prerequisites”- Omnia Enterprise license activated
- At least one ToolRegistry deployed
- For claim-based rules: an AgentPolicy with
claimMappingconfigured (see Configure Agent Policies)
Write a CEL Deny Rule
Section titled “Write a CEL Deny Rule”CEL (Common Expression Language) rules evaluate against request headers and body. A rule denies the request when its expression evaluates to true.
apiVersion: omnia.altairalabs.ai/v1alpha1kind: ToolPolicymetadata: name: refund-guardrails namespace: productionspec: selector: registry: customer-tools tools: - process_refund rules: - name: max-refund-amount description: "Cap refunds at $500" deny: cel: 'double(body.amount) > 500.0' message: "Refund amount exceeds the $500 limit"Access Request Body Fields
Section titled “Access Request Body Fields”The body variable contains the parsed JSON request body:
# Check for a specific field value- name: block-status deny: cel: 'has(body.status) && body.status == "cancelled"' message: "Cannot process cancelled orders"
# Check numeric ranges- name: quantity-limit deny: cel: 'has(body.quantity) && int(body.quantity) > 100' message: "Quantity exceeds maximum of 100"Access Request Headers
Section titled “Access Request Headers”The headers variable contains all HTTP headers as a string map:
- name: require-internal-source deny: cel: '!("X-Source" in headers) || headers["X-Source"] != "internal"' message: "Only internal requests are allowed"Use String Extensions
Section titled “Use String Extensions”CEL string extensions are available for pattern matching:
- name: block-external-urls deny: cel: 'has(body.url) && !body.url.startsWith("https://internal.")' message: "Only internal URLs are permitted"
- name: block-sql-patterns deny: cel: 'has(body.query) && body.query.matches("(?i)(DROP|DELETE|TRUNCATE)")' message: "Destructive SQL operations are not allowed"Require JWT Claims
Section titled “Require JWT Claims”Ensure that specific claims are present before any CEL rules run. This is useful for enforcing that identity propagation is configured correctly.
spec: requiredClaims: - claim: Team message: "Team claim is required — ensure your AgentPolicy has claimMapping configured" - claim: Customer-Id message: "Customer ID is required for this tool"Required claims check for the presence of X-Omnia-Claim-<Claim> headers. These headers are populated by an AgentPolicy’s claimMapping section.
Inject Headers into Upstream Requests
Section titled “Inject Headers into Upstream Requests”Add headers to the request after policy evaluation passes. Use static values or CEL expressions:
spec: headerInjection: # Static header - header: X-Policy-Version value: "v2"
# Forward a claim as a different header - header: X-Tenant-Id cel: 'headers["X-Omnia-Claim-Customer-Id"]'
# Compute a value from multiple inputs - header: X-Audit-Trail cel: 'headers["X-Omnia-Agent-Name"] + "/" + headers["X-Omnia-Session-Id"]'Use Audit Mode for Dry-Run
Section titled “Use Audit Mode for Dry-Run”Start with audit mode to see what would be denied without blocking requests:
apiVersion: omnia.altairalabs.ai/v1alpha1kind: ToolPolicymetadata: name: new-limits namespace: productionspec: selector: registry: customer-tools rules: - name: strict-amount-check deny: cel: 'double(body.amount) > 100.0' message: "Amount exceeds strict limit" mode: audit # Log violations without blockingThe proxy logs audit decisions with wouldDeny: true:
{ "msg": "policy_decision", "decision": "deny", "wouldDeny": true, "mode": "audit", "policy": "new-limits", "rule": "strict-amount-check", "path": "/v1/refund", "method": "POST"}Once satisfied, switch to enforce:
spec: mode: enforceConfigure Audit Logging and Redaction
Section titled “Configure Audit Logging and Redaction”Enable full decision logging and redact sensitive fields:
spec: audit: logDecisions: true redactFields: - credit_card - ssn - api_key - passwordWith logDecisions: true, every request (allowed and denied) generates a structured log entry. Fields listed in redactFields have their values masked in log output.
Apply a Policy to All Tools in a Registry
Section titled “Apply a Policy to All Tools in a Registry”Omit the tools list in the selector to match every tool in the registry:
spec: selector: registry: customer-tools # No tools list — matches all tools in this registry rules: - name: require-auth-header deny: cel: '!("Authorization" in headers)' message: "Authorization header is required"Verify Policy Status
Section titled “Verify Policy Status”Check that your policies are active and rules compiled:
kubectl get toolpolicies -n productionExpected output:
NAME REGISTRY MODE PHASE RULES AGErefund-guardrails customer-tools enforce Active 1 5mnew-limits customer-tools audit Active 1 2mIf a policy shows Error phase, describe it to see the compilation error:
kubectl describe toolpolicy refund-guardrails -n productionCommon CEL Patterns
Section titled “Common CEL Patterns”Claim-based access control
Section titled “Claim-based access control”- name: team-restriction deny: cel: 'headers["X-Omnia-Claim-Team"] != "finance"' message: "Only the finance team can use this tool"Time-based restrictions
Section titled “Time-based restrictions”- name: business-hours-only deny: cel: 'int(headers["X-Request-Hour"]) < 9 || int(headers["X-Request-Hour"]) > 17' message: "This tool is only available during business hours"Multiple conditions
Section titled “Multiple conditions”- name: high-value-finance-only deny: cel: 'double(body.amount) > 1000.0 && headers["X-Omnia-Claim-Team"] != "finance"' message: "Only the finance team can process amounts over $1000"Related Resources
Section titled “Related Resources”- ToolPolicy CRD Reference — full field specification
- Policy Engine Architecture — how policies work
- Configure Agent Policies — network-level policies
- Securing Agents with Policies — end-to-end tutorial