Docs/Policies/Writing Policies

Writing Policies

A step-by-step guide to authoring MAPL policies for your organization. Learn how to design policy hierarchies and implement real-world access patterns.

1

Plan Your Hierarchy

Before writing policies, map your organization's structure to policy levels:

Organization
├── company:acme           ← Company-wide defaults
│   ├── bu:engineering     ← Engineering business unit
│   │   ├── team:backend   ← Backend team
│   │   │   ├── user:alice ← Individual user
│   │   │   └── user:bob
│   │   └── team:frontend
│   └── bu:finance
│       └── team:analysts

Questions to Answer

  • • What resources should everyone access?
  • • What's different between business units?
  • • What team-specific restrictions exist?
  • • Do any users need special permissions?

Best Practices

  • • Start broad at the top, restrict going down
  • • Keep organization policies minimal
  • • Don't over-specialize at the user level
  • • Use teams to group similar users

2

Write the Root Policy

Start with your organization's root policy. This defines the broadest permissions that all child policies inherit from:

company-acme.json
{
  "policy_id": "company:acme",
  "version": "1.0",
  "description": "Acme Corp - Company-wide base policy",
  "scope": "org",

  "resources": [
    "llm:openai/*",
    "llm:anthropic/*",
    "tool:calculator/*"
  ],

  "denied_resources": [
    "*.secret",
    "*.password",
    "admin:**"
  ],

  "constraints": {
    "rate_limit": 1000,
    "parameters": {
      "llm:**": {
        "max_tokens": {"max": 8000}
      }
    }
  }
}

Key Points

  • resources: Define what everyone CAN potentially access
  • denied_resources: Block dangerous patterns for all users
  • constraints: Set upper bounds that children cannot exceed

3

Add Business Unit Policies

Business unit policies inherit from the company policy and add BU-specific restrictions:

bu-engineering.json
{
  "policy_id": "bu:engineering",
  "extends": "company:acme",
  "description": "Engineering BU - Code and tools access",
  "scope": "bu",

  "resources": [
    "tool:github/*",
    "tool:database/query"
  ],

  "constraints": {
    "rate_limit": 500,
    "parameters": {
      "llm:**": {
        "max_tokens": {"max": 4000}
      }
    }
  }
}

Notice: Engineering adds GitHub and database access (domain-aware inheritance), but restricts token limits from 8000 to 4000.


4

Define Team Policies

Team policies specialize further based on team responsibilities:

team-backend.json
{
  "policy_id": "team:backend",
  "extends": "bu:engineering",
  "description": "Backend team - Database and API access",
  "scope": "team",

  "resources": [
    "tool:database/*",
    "tool:api/*"
  ],

  "constraints": {
    "rate_limit": 200,
    "parameters": {
      "llm:**": {
        "model": ["gpt-4", "claude-3-sonnet"],
        "max_tokens": {"max": 2000}
      },
      "tool:database/*": {
        "tables": {
          "allowed_values": ["users", "orders", "products", "logs"]
        }
      }
    }
  }
}

5

Optional: User-Specific Policies

Most users should inherit from their team policy without customization. Only create user policies when truly necessary:

Good Reasons for User Policies

  • • Special project access (time-limited)
  • • Additional restrictions (probation, compliance)
  • • Role-specific tools (tech lead, on-call)

Bad Reasons for User Policies

  • • Granting more permissions (use group instead)
  • • One-off exceptions (creates maintenance burden)
  • • Personal preference (not a security concern)

6

Deploy and Test

Create and test your policies using the Console:

1. Create Policies

  1. Go to Console → Policies
  2. Click Create Policy
  3. Paste your policy JSON and click Save
  4. The Console validates syntax automatically on save

2. View Inheritance Chain

  1. Click on any policy to open the detail view
  2. The Inheritance section shows the full policy chain
  3. Click Show Effective Policy to see the merged result

3. Test with Real Requests

Write a simple test script to verify your policies work as expected:

from macaw_adapters.openai import SecureOpenAI

# Test as a specific user
client = SecureOpenAI(
    app_name="policy-test",
    jwt_token=alice_jwt  # Alice's token
)

# This should succeed if alice has access
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello"}],
    max_tokens=1000
)

4. Check Audit Logs

  1. Go to Console → Logs
  2. Find your test requests
  3. Verify ALLOWED or DENIED matches expectations
  4. Click events to see which policy was applied

Common Policy Patterns

Read-Only Access

"resources": [
  "tool:database/query",      // Allow reads
  "tool:reports/view"
],
"denied_resources": [
  "tool:database/insert",     // Block writes
  "tool:database/update",
  "tool:database/delete"
]

Cost Control (Token Limits)

"constraints": {
  "parameters": {
    "llm:**": {
      "model": ["gpt-3.5-turbo"],  // Cheaper model only
      "max_tokens": {"max": 500}    // Limited output
    }
  }
}

Human Approval for High-Value Operations

"attestations": [
  "manager_approval::{params.amount > 10000}"
],
"constraints": {
  "attestations": {
    "manager_approval": {
      "approval_criteria": "role:manager",
      "timeout": 300,
      "time_to_live": 3600
    }
  }
}

Next Steps