Skip to content

[Draft] OPA Plugin: Mapping Cedar via Rego

Safin Wasi edited this page Apr 17, 2026 · 2 revisions

Introduction

Open Policy Agent allows us to extend the behavior of the OPA runtime via plugins. This lets us define custom behavior such as logging or executing extra Go code. Using the cedarling_go binding, we are thus able to run an instance of Cedarling inside the OPA binary.

Currently, the cedarling_opa plugin simply boots the Cedarling with a configurable bootstrap file and does not provide any additional functionality. This wiki page is for the purposes of documenting the mapping from Rego to Cedarling concepts in order to implement rego verbs and functions.

Execution Flow

sequenceDiagram
    participant Client
    participant OPA
    participant Rego
    participant Builtin as cedarling_opa.authorize
    participant Plugin as Cedarling Binding (Go)
    participant Cedarling
    participant Cedar

    Client->>OPA: Query (input)
    OPA->>Rego: Evaluate rego policy

    Rego->>Builtin: cedarling_opa.authorize(input)

    Builtin->>Plugin: Invoke Go built-in
    Plugin->>Cedarling: Build + send request
    Cedarling->>Cedar: Evaluate cedar policies

    Cedar-->>Cedarling: Decision + diagnostics
    Cedarling-->>Plugin: Result
    Plugin-->>Builtin: Normalized JSON

    Builtin-->>Rego: result
    Rego-->>OPA: decision object

    OPA-->>Client: Response
Loading

In this flow, Rego acts as a thin wrapper between the OPA runtime and the cedarling_go binding. The intended way to use this would be to avoid complex Rego policies; instead, Rego simply calls the new verbs authorize and authorize_unsigned, while the Cedar policies are considered to be the source of truth.

Mapping between Cedarling and OPA

Cedar Concept Cedarling API Rego/OPA Equivalent
Principal EntityData input.principal
Action String input.action
Resource EntityData input.resource
Context Dictionary input.context
Decision Allow/Deny allow boolean
Diagnostics reason() trace? logging?

Unsigned Authorization

Input spec:

{
  "principal": {
    "cedar_entity_mapping": {
      "entity_type": "User",
      "id": "some_id"
    }
  }
  "action": "read",
  "resource": {
    "cedar_entity_mapping": {
      "entity_type": "Document",
      "id": "some_document"
    }
  },
  "context": {}
}

Output spec:

{
  "decision": true,
  "reasons": ["policy-1"],
  "errors": [],
  "request_id": "uuid"
}

Rego example:

package cedarling_opa

default allow := false

result := cedarling_opa.authorize_unsigned(input) # new rego verb: authorize_unsigned

allow {
	result.decision
}

deny_reasons := result.reasons

Multi-issuer authorization

Input spec:

{
  "tokens": [
    {
        "mapping": "Jans::Access_token",
        "payload": "eyJhbGciOiJIUzI1NiIs..."
    }
  ],
  "action": "read",
  "resource": {
    "type": "Document",
    "id": "doc1",
    "attrs": {}
  },
  "context": {}
}

Output spec:

{
  "decision": true,
  "reasons": ["policy-1"],
  "errors": [],
  "request_id": "uuid"
}

Rego Example:

package cedarling_opa

default allow := false

result := cedarling_opa.authorize(input) # new rego verb: authorize

allow {
	result.decision
}

deny_reasons := result.reasons

Clone this wiki locally