Vertesia Documentation

Attribute-Based Access Control

The role model grants access to named people on named resources. Attribute-Based Access Control (ABAC) adds a second way to write rules: by attributes. Instead of "Alice can read this collection," you write "anyone in the Finance department can read documents labelled Finance," or "users with clearance 3 or higher can read documents classified Confidential or below."

Rules adapt as people and content change: a new hire who joins the Finance group is covered when their attributes match. Principal attributes and matching rules are resolved when an access token is issued, so refresh the user's session or issue a new API-key token before testing a policy change.

The two kinds of attribute rules

ABAC rules are still Access Control Entries, but instead of pointing at a fixed principal or resource they match by conditions:

  • Principal Set — matches who by their attributes (a user's department, tags, clearance; whether the caller is a user or an API key). Evaluated when a token is issued: the match decides whether the rule even enters that person's session.
  • Resource Set — matches which content by its attributes (a document's sensitivity, its properties, its type). Evaluated when content is queried: the match decides which documents the rule lets through.

A rule can combine both: a Principal Set on the "who" side and a Resource Set on the "what" side. That pairing — these principals get this role on content matching these conditions — is the heart of attribute-based and clearance-based access.

Writing conditions

A condition is a field, an operator, and a value. Multiple conditions in one rule are combined with AND.

OperatorMeaningSupported in
$eq / $neequals / does not equalPrincipal Sets and Resource Sets
$gt / $gte / $lt / $ltegreater / less thanPrincipal Sets and root-level numeric Resource Set fields
$in / $ninis / is not one of a listPrincipal Sets and Resource Sets
$existsthe field is present (or absent)Principal Sets and Resource Sets
$emptythe field is empty (or non-empty)Principal Sets and Resource Sets
$likecase-insensitive wildcard text match, where * matches anythingPrincipal Sets only

Where the field name goes depends on what it is:

  • Principal fields sit at the root of Principal Set conditions: clearance, compartments, tags, email, and kind (user or apikey).
  • Content classification fields sit at the root of Resource Set conditions: sensitivity, compartments, and tags.
  • Custom attributes sit under properties. — for example properties.department, properties.region.

Referring to the person in a content rule

Inside a Resource Set, a value may reference the requesting person with the $principal. prefix. It is resolved to that person's own value when their token is issued, then matched against each document.

{ "sensitivity": { "$lte": "$principal.clearance" } }

Read this as "only show documents whose sensitivity is at most the viewer's own clearance" — the classic "no read up" rule. $principal. works only inside Resource Set (content) conditions; it has no effect on the principal side.

Two kinds of roles

Roles are split into two partitions, and the platform always checks the built-in set first so custom roles can never shadow it:

  • System roles — the built-in roles from the role model: owner, admin, developer, reader, and so on. These govern the platform as a whole.

  • ABAC content roles — a separate, content-only set defined for attribute rules:

    RoleGrants
    content:readerread
    content:writerread, write
    content:managerread, write, delete

When you build an attribute rule over content, you use a content role, not a system role. This keeps the two worlds cleanly separated: system roles decide what someone can do across the platform; content roles decide, attribute by attribute, which documents they reach.

Document scope and collection scope

A content role applies to a scope — either document (the default) or collection. The same content:reader / content:writer / content:manager roles serve both; the scope you choose on the rule decides whether it governs documents or collections. This distinction matters for restriction, below.

Classification: clearance, compartments, and sensitivity

ABAC has first-class support for a Bell-LaPadula (BLP) style classification model, so you can express clearance-based access without hand-writing conditions.

On people (users, groups, and API keys):

  • Clearance — a level from 0 to 4. The higher the clearance, the more sensitive the content the person may reach.
  • Compartments — named need-to-know areas (for example engineering, hr, legal). A person only reaches content in compartments they hold.

On content (documents and collections):

  • Sensitivity — the same 0–4 scale, labelled Public, Internal, Confidential, Restricted, Secret.
  • Compartments — the areas a document belongs to.

The two canonical rules, written as Resource Set conditions:

{ "sensitivity": { "$lte": "$principal.clearance" } }
{ "compartments": { "$in": "$principal.compartments" } }

Together: a person sees a document only when its sensitivity is within their clearance and they share at least one of its compartments. For write access you invert the sensitivity comparison ($gte) — the "no write down" rule — so classified information cannot be copied into a less-classified document.

Advanced: unclassified content

Documents created before classification was enabled may have no sensitivity or compartments at all. So a clearance rule does not silently hide them, the platform treats unclassified content as public: any rule that references a classification field automatically also allows documents where that field is absent or empty. When you roll classification out, plan to set a baseline sensitivity on existing content, or lean on this fallback during the transition.

Turning restriction on: the Restrict Mode preset

By default a project is open: its content is visible to members through the role model, and attribute rules only add access. To make attributes the gate — nothing visible unless a rule grants it — you switch the project into restrict mode.

The IAM permissions screen has a one-click Restrict Mode preset. It creates a single rule that pairs a wildcard Principal Set (named BLP Restrict Mode, matching everyone) with a Resource Set (named Deny All (BLP)) whose condition matches no real document. The effect: every person now carries a content-security context, which drops the project:* default. A resource remains available when it directly names that user or one of their groups, or when another ABAC rule grants access. Create and test the real granting rules first, apply Restrict Mode, refresh test tokens, and then expand the rollout.

The companion Open Mode preset does the reverse — a wildcard rule granting everyone read access to all content — to return a project to open.

Advanced: how restriction reaches the query

Attribute rules are resolved when a token is issued, not when content is queried. Each matched rule contributes its role's verbs to a content-security block in the caller's session, keyed by scope — a document-scope rule contributes bare read / write / delete keys, while a collection-scope rule contributes collection:read / collection:write / collection:delete. At query time the content service reads only the keys for the scope it is filtering and turns each rule's conditions into an OR filter; there is no cross-scope fallback by design, which is exactly why a document restriction does not touch collections. If no key exists for a scope, that scope stays in open mode. Because all of the "who can see what" logic is settled at token time, the query path stays a simple, fast filter.

Token lifecycle

Role assignments, group membership, principal attributes, and matching Principal Sets are captured when the access token is issued. After changing any of them, refresh or restart the user's authenticated session. For an API key, issue a new access token. Long-running agents inherit the effective user's conditions when their agent token is created, so start a fresh run when validating an updated policy.

Where to go next

Was this page helpful?