Policy Document Format

Each Policy entity contains a document field stored as JSON. This page describes the schema and evaluation semantics of that document.

Schema

{
  "Version": "2024-01-01",
  "Statement": [
    {
      "Sid":        "<optional statement identifier>",
      "Effect":     "Allow | Deny",
      "Action":     ["<service>:<Action>", ...],
      "Resource":   ["<FRN pattern>", ...],
      "Condition":  {
        "<Operator>": {
          "<condition-key>": "<value> | [<values>]"
        }
      }
    }
  ]
}

Fields

Version

Optional policy document version string (e.g. "2024-01-01"). Reserved for future schema evolution.

Statement

Required top-level array. If absent or empty, the policy produces no matches and is effectively a no-op.

Sid

Optional human-readable statement identifier. Returned as matchedStatement in authorization responses for traceability.

Effect

Required. Must be "Allow" or "Deny" (case-sensitive).

  • "Deny" statements are evaluated first and always win over "Allow" statements.

  • If no statement matches, the result is a default deny.

Action

Required. A single action string or an array of action strings. Each entry uses a service:Action convention. Matching rules:

Pattern

Matches

"devices:Read"

Only the exact action devices:Read

"devices:*"

Any action starting with devices:

"*"

Any action

Resource

Required. A single FRN string/pattern or an array of FRN strings/patterns. See FRN Specification for the full wildcard and matching rules.

Special case: a single-element array ["*"] or the string "*" matches any resource.

Condition

Optional object. When present, all operators must pass for the statement to match (AND logic across operators).

Each operator maps condition keys to expected values. Values may be a single string or an array of strings.

Supported Operators

Operator

Semantics

StringEquals

The actual context value must be in the expected list (exact match).

StringNotEquals

The actual context value must not be in the expected list.

StringLike

The actual value must match at least one glob pattern (* is converted to .* for regex matching).

Bool

actual.toString() must be in the expected list (e.g., "true" or "false").

Condition keys may carry a dotid: prefix which is stripped before context lookup. Context keys are also tried in snake_case form (e.g., principalType is also tried as principal_type).

Unknown operators evaluate to false and produce a warning log.

Example

The following policy allows reading and listing devices for user principals, while explicitly denying deletion of any device:

{
  "Version": "2024-01-01",
  "Statement": [
    {
      "Sid": "AllowDeviceRead",
      "Effect": "Allow",
      "Action": ["devices:Read", "devices:List"],
      "Resource": ["frn:*:devices:device/*"],
      "Condition": {
        "StringEquals": {
          "dotid:principalType": "user"
        }
      }
    },
    {
      "Sid": "DenyDeviceDelete",
      "Effect": "Deny",
      "Action": ["devices:Delete"],
      "Resource": ["frn:*:devices:device/*"]
    }
  ]
}

Evaluation order for this policy:

  1. The DenyDeviceDelete statement is checked first (deny pass). If the requested action is devices:Delete on any device FRN, the result is DENY immediately.

  2. The AllowDeviceRead statement is checked next (allow pass). If the action is devices:Read or devices:List on any device FRN and the context contains principalType = "user", the result is ALLOW.

  3. Any other action/resource combination results in a default DENY (no match).