Olympus Docs
SecurityAuthorization

Authorization, OPA integration

Open Policy Agent for fine-grained authz

Open Policy Agent (OPA) is a general-purpose policy engine. Rego, its policy language, expresses authz decisions concisely. Pairs well with Olympus's auth.

Architecture

Your app
  ↓ "Can user X do action Y on resource Z?"
OPA (sidecar or library)
  ↓ evaluates Rego policy
  ↓ returns true/false (and reason)
Your app proceeds or denies

OPA doesn't authenticate (that's Olympus). It decides what authenticated users can do.

Deploy modes

A: Sidecar

OPA runs as a separate process; your app calls its HTTP API:

# Add to your compose
opa:
  image: openpolicyagent/opa:latest
  command: run --server --addr :8181 /policies
  volumes:
    - ./policies:/policies:ro

Your app posts:

const response = await fetch("http://opa:8181/v1/data/olympus/authz/allow", {
  method: "POST",
  body: JSON.stringify({
    input: {
      subject: { sub: session.id, role: session.role },
      action: "delete",
      resource: { id: doc.id, owner_id: doc.owner }
    }
  })
});
const { result } = await response.json();
if (!result) return Response.json({ error: "forbidden" }, { status: 403 });

B: Embedded

Use OPA as a Go library, embed in your service. Lower latency than the sidecar, but couples policy and code lifecycle.

Example policy

policies/olympus.rego:

package olympus.authz

import future.keywords.if

default allow := false

# Owners always allowed
allow if {
  input.subject.sub == input.resource.owner_id
}

# Admins can read anything
allow if {
  input.subject.role == "admin"
  input.action == "read"
}

# Department members can edit their own department's resources
allow if {
  input.subject.department == input.resource.department
  input.action in {"read", "write"}
}

# Deny if classified beyond clearance
allow := false if {
  input.resource.classification == "secret"
  input.subject.clearance_level < 3
}

Policy testing

Rego is testable:

package olympus.authz_test

test_owner_can_delete if {
  allow with input as {
    "subject": {"sub": "alice"},
    "action": "delete",
    "resource": {"owner_id": "alice"}
  }
}

test_non_owner_cannot_delete if {
  not allow with input as {
    "subject": {"sub": "bob", "role": "user"},
    "action": "delete",
    "resource": {"owner_id": "alice"}
  }
}

Run with opa test policies/.

Policy bundles

For production, distribute policies via OPA bundles:

  1. CI builds the bundle on every policy change.
  2. Bundle published to S3 / GCS / GitHub release.
  3. OPA polls the bundle URL; new policies hot-reload.

Changes propagate without restarting your app.

Decision logs

OPA can ship every decision to a sink (Kafka, HTTP, etc.). Useful for:

  • Audit (every authz decision is recorded).
  • Debugging ("why was this denied?", look at the decision log).
  • Compliance (SOC 2 evidence).

Performance

OPA decision: ~10-100 microseconds typical. For most apps, this is below the noise floor.

Where to learn more

On this page