Skip to main content
Hexr uses Open Policy Agent (OPA) to evaluate authorization decisions for every request your agents make to cloud services or platform APIs. Before any credential exchange happens, OPA checks whether the requesting agent’s SPIFFE identity is permitted to access the requested service. You write the rules in Rego, deploy them as Kubernetes ConfigMaps, and Hexr enforces them at runtime — without touching your agent code.

How OPA fits into the request flow

Every outbound request from an agent passes through Envoy, which calls OPA before forwarding:
Agent → Envoy → OPA (allow/deny?) → Credential Injector → Cloud STS
OPA receives the agent’s verified SPIFFE identity and the requested service, evaluates your Rego policies, and returns allow or deny. A denied request never reaches the credential exchange.

Policy input

OPA receives this input for every request:
{
  "spiffe_id": "spiffe://hexr.cloud/agent/acme-corp/content-crew/researcher",
  "tenant": "acme-corp",
  "agent": "content-crew",
  "role": "researcher",
  "service": "gcp_bigquery",
  "action": "query",
  "timestamp": "2026-01-15T10:30:00Z"
}
Your policies can use any combination of these fields to make access decisions.

Example policies

Service access by role

The most common pattern — control which roles can access which services:
package hexr.authz

default allow = false

# Researchers can access BigQuery and S3 (read-only)
allow {
    input.role == "researcher"
    input.service in {"gcp_bigquery", "aws_s3"}
}

# Writers can only write to S3
allow {
    input.role == "writer"
    input.service == "aws_s3"
    input.action == "PutObject"
}

# Editors have no cloud access
# (implicitly denied by default allow = false)

Time-based access

Restrict access to business hours:
# Only allow access during business hours (UTC)
allow {
    input.role == "researcher"
    time.clock(time.now_ns())[0] >= 8    # After 8 AM
    time.clock(time.now_ns())[0] < 18    # Before 6 PM
}

Rate limiting

Prevent runaway agents from exhausting your quota:
# Allow max 100 tool calls per minute per agent
allow {
    count(recent_calls) < 100
}

recent_calls[call] {
    call := data.audit_log[_]
    call.agent == input.agent
    call.timestamp > time.now_ns() - 60000000000  # 1 minute
}

Deploying policies

Policies deploy as Kubernetes ConfigMaps and reload within 30 seconds of an update. On self-hosted deployments, apply the ConfigMap directly to your cluster:
apiVersion: v1
kind: ConfigMap
metadata:
  name: opa-policy
  namespace: hexr-system   # The namespace where Hexr runs
data:
  policy.rego: |
    package hexr.authz
    default allow = false
    allow {
      input.role == "researcher"
      input.service in {"gcp_bigquery", "aws_s3"}
    }
On Hexr Cloud, manage policies through the dashboard or contact support to apply custom policies to your tenant.
Policy changes reload within 30 seconds. You don’t need to restart any agents or platform services when you update a policy.

Testing policies

Use OPA’s built-in test framework to validate your policies before deploying them:
test_researcher_bigquery_allowed {
    allow with input as {
        "role": "researcher",
        "service": "gcp_bigquery",
        "action": "query"
    }
}

test_writer_bigquery_denied {
    not allow with input as {
        "role": "writer",
        "service": "gcp_bigquery",
        "action": "query"
    }
}
opa test ./policies/ -v
Write tests for both allowed and denied cases. The default allow = false pattern means untested paths are implicitly denied — but explicit tests document your intent and catch regressions when you update policies.