Policy Design
This guide covers best practices for designing policies that balance security with agent productivity.
Rule ordering
Policy rules are evaluated top-to-bottom, and the first matching rule wins. Order matters:
[
{ "action": "update_deal", "resource_pattern": "crm:deal:*", "decision": "require_approval", "risk_level": "high",
"conditions": { "require_approval_if_stage": ["closed_won"] }
},
{ "action": "update_deal", "resource_pattern": "crm:deal:*", "decision": "allow", "risk_level": "low" },
{ "action": "*", "resource_pattern": "*", "decision": "deny", "risk_level": "medium" }
]In this example:
- Closing a deal as won requires approval (most specific rule first)
- Other deal updates are allowed
- Everything else is denied (catch-all at the bottom)
Always place more specific rules before more general ones. A catch-all deny at the bottom ensures that unrecognized actions are blocked by default.
Resource patterns
Use wildcards strategically:
| Pattern | Matches | Use case |
|---|---|---|
crm:deal:123 | Exact resource | Lock down a specific high-value deal |
crm:deal:* | All deals | General deal policy |
crm:* | All CRM resources | Broad CRM policy |
* | Everything | Catch-all default |
Using conditions
Amount thresholds
Use max_amount_change to escalate large changes:
{
"action": "update_deal",
"resource_pattern": "crm:deal:*",
"decision": "allow",
"risk_level": "medium",
"conditions": {
"max_amount_change": 50000
}
}Deals under $50,000 are auto-approved. Larger changes require human review.
Stage gates
Use require_approval_if_stage for critical transitions:
{
"conditions": {
"require_approval_if_stage": ["closed_won", "closed_lost"]
}
}Field protection
Use deny_fields to prevent modification of sensitive fields:
{
"conditions": {
"deny_fields": ["owner_id", "created_at", "organization_id"]
}
}deny_fields results in a hard deny. If an agent’s payload contains any of the listed fields, the request is denied regardless of the base decision.
Common patterns
Permissive start
Begin with broad allow rules and tighten as you learn:
[
{ "action": "*", "resource_pattern": "*", "decision": "allow", "risk_level": "low" }
]Review receipts to identify risky actions, then add specific rules.
Deny by default
The safest approach — only allow explicitly listed actions:
[
{ "action": "read_deal", "resource_pattern": "crm:deal:*", "decision": "allow", "risk_level": "low" },
{ "action": "update_deal", "resource_pattern": "crm:deal:*", "decision": "require_approval", "risk_level": "high" },
{ "action": "*", "resource_pattern": "*", "decision": "deny", "risk_level": "medium" }
]Tiered risk
Assign risk levels to help approvers prioritize:
| Risk level | Use for |
|---|---|
low | Read operations, minor updates |
medium | Standard write operations |
high | Financial changes, deletions, stage transitions |
Testing with the simulator
Before activating a new policy version, use the policy simulator to verify behavior:
curl -X POST https://your-relynt-instance/v1/policy-simulator \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"action": "update_deal",
"resource": "crm:deal:123",
"payload": { "amount": 100000, "stage": "closed_won" }
}'Test edge cases:
- Requests that should be allowed
- Requests that should be denied
- Requests that should require approval
- Requests with boundary values (e.g., amount exactly at the threshold)