ArmorIQ LogoArmorIQ SDK
Concepts

Policy Management

Control agent execution with policies

Policy Management

Policies define what actions an agent can execute, providing fine-grained control over agent behavior. Think of policies as execution guardrails that work alongside intent verification.

What are Policies?

A policy is a set of rules that determines:

  • Which MCPs and actions are allowed/denied
  • Time-based access restrictions
  • Rate limits
  • IP whitelisting
  • Tool-level permissions

Policy Structure

{
  "allow": ["analytics-mcp/*", "data-mcp/fetch_*"],
  "deny": ["data-mcp/delete_*", "admin-mcp/*"],
  "allowed_tools": ["read_file", "analyze", "aggregate"],
  "rate_limit": 100,
  "ip_whitelist": ["10.0.0.0/8", "192.168.1.0/24"],
  "time_restrictions": {
    "allowed_hours": [9, 10, 11, 12, 13, 14, 15, 16, 17],
    "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
  },
  "priority": 50
}

Policy Fields

FieldTypeDescriptionExample
allowlist[str]Allowed MCP/action patterns (glob)["data-mcp/*"]
denylist[str]Denied MCP/action patterns (glob)["data-mcp/delete_*"]
allowed_toolslist[str]Whitelisted tool names["read_file", "analyze"]
rate_limitintMax requests per hour100
ip_whitelistlist[str]Allowed IPs/CIDR ranges["10.0.0.0/8"]
time_restrictionsobjectTime-based access controlSee below
priorityintPolicy priority (0-100, higher wins)50

Time Restrictions

{
  "allowed_hours": [9, 10, 11, 12, 13, 14, 15, 16, 17],  // 0-23
  "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
}

Creating Policies

Method 1: Programmatic (SDK)

Define policies directly in your code:

# Restrictive policy for production agent
policy = {
    "allow": ["analytics-mcp/*", "data-mcp/fetch_*"],
    "deny": ["data-mcp/delete_*"],
    "allowed_tools": ["read_file", "analyze", "aggregate"],
    "rate_limit": 100,
    "ip_whitelist": ["10.0.0.0/8"],
    "time_restrictions": {
        "allowed_hours": [9, 10, 11, 12, 13, 14, 15, 16, 17],
        "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
    }
}

token = client.get_intent_token(
    plan_capture=plan,
    policy=policy,
    validity_seconds=3600
)

Method 2: Visual Policy Builder (ArmorIQ Canvas)

Create policies using the drag-and-drop interface at platform.armoriq.ai/dashboard/policies:

Steps:

  1. Click "Canvas" button to open visual builder
  2. Drag users, MCPs, and agents onto canvas
  3. Connect entities with edges (connections)
  4. Click edge to configure permissions visually
  5. Use "Browse Tools" to select allowed tools from MCP
  6. Set IP restrictions, time windows, rate limits
  7. Save policy with name and priority

Use the policy ID in SDK:

# Use policy created in Canvas
token = client.get_intent_token(
    plan_capture=plan,
    policy_id="f88cf4c7-732d-44ff-901b-fd3d882c2ecf",  # From Canvas
    validity_seconds=3600
)

Or fetch policy JSON from API:

import requests

# Fetch policy from ArmorIQ API
policy_response = requests.get(
    f"https://customer-api.armoriq.ai/policies/f88cf4c7-732d-44ff-901b-fd3d882c2ecf",
    headers={"Authorization": f"Bearer {user_jwt}"}
)
policy = policy_response.json()["data"]["permissions"]

# Use fetched policy
token = client.get_intent_token(
    plan_capture=plan,
    policy=policy,
    validity_seconds=3600
)

Policy Evaluation

How Policies are Applied

When you request an intent token, ArmorIQ:

  1. Loads applicable policies (user, agent, organization level)
  2. Merges policies by priority (higher priority wins)
  3. Evaluates plan actions against merged policy
  4. Rejects token if any action violates policy
  5. Embeds policy hash in token

At invocation time, ArmorIQ:

  1. Extracts policy from token
  2. Checks if action matches allow/deny patterns
  3. Verifies time restrictions (if any)
  4. Checks rate limits
  5. Validates IP address (if whitelist exists)
  6. Allows or denies request

Allow/Deny Pattern Matching

Policies use glob patterns for flexible matching:

policy = {
    "allow": [
        "data-mcp/*",           # All data-mcp actions
        "analytics-mcp/fetch_*" # Only fetch actions in analytics-mcp
    ],
    "deny": [
        "data-mcp/delete_*",    # No delete actions
        "admin-mcp/*"           # No admin actions at all
    ]
}

Matching Rules:

  • * matches any string
  • data-mcp/* matches data-mcp/fetch, data-mcp/analyze, etc.
  • data-mcp/fetch_* matches data-mcp/fetch_users, data-mcp/fetch_orders, etc.
  • Deny takes precedence over allow

Priority Resolution

When multiple policies apply:

# User-level policy (priority 30)
user_policy = {
    "allow": ["data-mcp/*"],
    "priority": 30
}

# Agent-level policy (priority 60)
agent_policy = {
    "deny": ["data-mcp/delete_*"],
    "priority": 60
}

# Organization-level policy (priority 90)
org_policy = {
    "allow": ["analytics-mcp/*"],
    "priority": 90
}

# Merged result:
# - data-mcp/* allowed (user policy)
# - data-mcp/delete_* denied (agent policy, higher priority)
# - analytics-mcp/* allowed (org policy, highest priority)

Policy Examples

Example 1: Read-Only Agent

# Agent can only read data, no writes
readonly_policy = {
    "allow": [
        "data-mcp/fetch_*",
        "data-mcp/query_*",
        "analytics-mcp/analyze_*"
    ],
    "deny": [
        "data-mcp/insert_*",
        "data-mcp/update_*",
        "data-mcp/delete_*"
    ],
    "rate_limit": 1000
}

Example 2: Business Hours Only

# Agent only works during business hours
business_hours_policy = {
    "allow": ["*"],
    "time_restrictions": {
        "allowed_hours": [9, 10, 11, 12, 13, 14, 15, 16, 17],
        "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
    }
}

Example 3: High-Security Agent

# Agent with strict security constraints
secure_policy = {
    "allow": ["finance-mcp/fetch_balance", "finance-mcp/calculate_*"],
    "deny": ["finance-mcp/transfer_*", "finance-mcp/withdraw_*"],
    "ip_whitelist": ["10.0.0.0/8"],  # Internal network only
    "rate_limit": 50,
    "time_restrictions": {
        "allowed_hours": [9, 10, 11, 12, 13, 14, 15, 16, 17],
        "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
    }
}

Example 4: Development Agent

# Permissive policy for development
dev_policy = {
    "allow": ["*"],
    "deny": ["production-mcp/*"],  # No production access
    "rate_limit": 10000
}

Policy Composition

You can compose policies for different scenarios:

def get_policy(environment: str, role: str) -> dict:
    """Get policy based on environment and role."""
    
    base_policy = {
        "rate_limit": 100,
        "priority": 50
    }
    
    # Environment-specific
    if environment == "production":
        base_policy["ip_whitelist"] = ["10.0.0.0/8"]
        base_policy["time_restrictions"] = {
            "allowed_hours": list(range(9, 18)),
            "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
        }
    
    # Role-specific
    if role == "admin":
        base_policy["allow"] = ["*"]
        base_policy["rate_limit"] = 1000
    elif role == "analyst":
        base_policy["allow"] = ["data-mcp/fetch_*", "analytics-mcp/*"]
        base_policy["deny"] = ["data-mcp/delete_*"]
    elif role == "viewer":
        base_policy["allow"] = ["data-mcp/fetch_*"]
        base_policy["deny"] = ["*"]
    
    return base_policy

# Usage
policy = get_policy(environment="production", role="analyst")
token = client.get_intent_token(plan_capture=plan, policy=policy)

Testing Policies

1. Dry Run Validation

# Validate policy without executing
try:
    token = client.get_intent_token(
        plan_capture=plan,
        policy=test_policy,
        dry_run=True  # Don't create token, just validate
    )
    print("✓ Policy is valid")
except PolicyViolationError as e:
    print(f"✗ Policy violation: {e}")

2. Policy Simulation

# Test if action would be allowed
def simulate_policy(policy: dict, mcp: str, action: str) -> bool:
    """Check if action would be allowed by policy."""
    full_action = f"{mcp}/{action}"
    
    # Check deny patterns
    for pattern in policy.get("deny", []):
        if fnmatch.fnmatch(full_action, pattern):
            return False
    
    # Check allow patterns
    for pattern in policy.get("allow", []):
        if fnmatch.fnmatch(full_action, pattern):
            return True
    
    return False

# Usage
policy = {"allow": ["data-mcp/*"], "deny": ["data-mcp/delete_*"]}
print(simulate_policy(policy, "data-mcp", "fetch_data"))  # True
print(simulate_policy(policy, "data-mcp", "delete_all"))  # False

Policy Management Best Practices

1. Start Restrictive, Then Relax

# Start with minimal permissions
initial_policy = {
    "allow": ["data-mcp/fetch_data"],
    "deny": ["*"]
}

# Add permissions as needed
expanded_policy = {
    "allow": ["data-mcp/fetch_*", "analytics-mcp/analyze"],
    "deny": ["data-mcp/delete_*"]
}

2. Use Environment-Specific Policies

policies = {
    "development": {
        "allow": ["*"],
        "deny": ["production-mcp/*"],
        "rate_limit": 10000
    },
    "staging": {
        "allow": ["*"],
        "deny": ["production-mcp/*"],
        "rate_limit": 1000
    },
    "production": {
        "allow": ["data-mcp/fetch_*", "analytics-mcp/*"],
        "deny": ["data-mcp/delete_*"],
        "rate_limit": 100,
        "ip_whitelist": ["10.0.0.0/8"]
    }
}

env = os.getenv("ENVIRONMENT", "development")
policy = policies[env]

3. Version Your Policies

policy_v1 = {
    "version": "1.0.0",
    "allow": ["data-mcp/*"],
    "deny": []
}

policy_v2 = {
    "version": "2.0.0",
    "allow": ["data-mcp/*", "analytics-mcp/*"],
    "deny": ["data-mcp/delete_*"]
}

# Use version in metadata
token = client.get_intent_token(
    plan_capture=plan,
    policy=policy_v2,
    metadata={"policy_version": "2.0.0"}
)

4. Monitor Policy Violations

# Log policy violations for security monitoring
try:
    token = client.get_intent_token(plan_capture=plan, policy=policy)
except PolicyViolationError as e:
    logger.error(f"Policy violation: {e}", extra={
        "user_id": user_id,
        "agent_id": agent_id,
        "violated_action": e.action,
        "policy": policy
    })
    raise

Common Policy Patterns

Pattern 1: Separation of Concerns

# Data team: Read-only access to data
data_team_policy = {
    "allow": ["data-mcp/fetch_*", "data-mcp/query_*"],
    "deny": ["data-mcp/insert_*", "data-mcp/delete_*"]
}

# Analytics team: Read + compute
analytics_team_policy = {
    "allow": ["data-mcp/fetch_*", "analytics-mcp/*"],
    "deny": ["data-mcp/insert_*", "data-mcp/delete_*"]
}

# Admin team: Full access
admin_team_policy = {
    "allow": ["*"],
    "deny": []
}

Pattern 2: Progressive Permissions

# Level 1: Basic access
level1_policy = {
    "allow": ["data-mcp/fetch_public_*"],
    "rate_limit": 100
}

# Level 2: Intermediate access
level2_policy = {
    "allow": ["data-mcp/fetch_*", "analytics-mcp/basic_*"],
    "rate_limit": 500
}

# Level 3: Advanced access
level3_policy = {
    "allow": ["data-mcp/*", "analytics-mcp/*"],
    "deny": ["data-mcp/delete_*"],
    "rate_limit": 1000
}

Next Steps

On this page