Skip to main content

Restrict access to individual records with ABAC policies

Permissions answer may this caller read entities? An ABAC policy — attribute-based access control — answers may this caller read this entity?, using attributes of the caller, of the record, and of the request.

Reach for one when a permission code is too coarse: everyone in the role needs entity.read, but some records inside it must stay out of reach.

Before you start

  • abac-policy.create to author policies, and abac-policy.read to review them.
  • The roles you intend to target already exist (compose roles).

1. Understand deny-overrides before you write anything

This is the one thing to internalise, because it is where the model differs from most others:

A deny always wins. Not "the highest-priority rule wins", not "the most specific rule wins" — if any policy denies the request, the request is denied, whatever else allows it. Priority orders the list on screen; it is not part of the decision.

The base is allow. Policies are a deny overlay on top of the permissions you have already granted, not a second allow-list you must opt into. A record with no matching policy is reachable if the caller's permissions allow it.

So write policies as denials of what must not be reachable, and let permissions do the granting.

2. Choose the condition that expresses the restriction

The ABAC policies screen listing four deny policies with their effect, priority, state and condition chips Four policies, all denials, each scoped differently: by entity type, by an attribute value, by relationship, and by consent. The Conditions column summarises what each one keys on.

Four kinds of condition are enforced against the record itself:

ConditionDenies unless…Use it for
Entity typethe record is of an allowed typeKeeping one role out of a whole class of record
Attribute valuethe record's attribute matchesRecords carrying a classification, jurisdiction, or flag
Relationshipthe caller is related to the record"Only the people related to this customer may open it"
Consentan active consent of a given type covers the recordProcessing that is lawful only while consent stands

A policy may also narrow by who is asking (roles, groups, the caller's own attributes), by which action, and by request context such as the caller's network.

3. Author the policy

The new ABAC policy form, showing the effect, the priority field labelled sort-only, and the subject and action sections The authoring form states the model on the form itself: "A deny always wins. Priority only changes the sort order, never the decision" — and the priority field is labelled (sort only). Below the effect come the subject (who), the action, and the conditions.

Give it a name a colleague will understand a year from now — the name is what appears in the audit trail and in the denial a steward reports to you.

Two guards refuse a policy at save time rather than letting you discover the problem in production:

A denial with no conditions is refused

A policy that would match every request is rejected when you save it. Under deny-overrides it would lock the tenant out of its own data — including out of the screen needed to remove the policy.

Referential integrity is checked too: a policy naming a permission code, role, relationship type, or consent type that does not exist is refused. A policy cannot silently do nothing because of a typo.

A saved ABAC policy, showing its effect, priority, description, subject roles and action codes A saved policy: the effect, the priority marked (sort only), who it applies to, and the actions it covers. The conditions follow below. A Recent matches tab shows where it has actually fired — which is what to open when a steward reports being refused.

4. Know where it is enforced

A policy is evaluated twice, and the second time is why it holds:

  • At the request boundary, against what is known before any record is loaded — who is asking, which action, the request context.
  • Against each record, once loaded.

That second point is what makes the behaviour predictable in lists. When the record you asked for directly is denied, the request is refused. When a record inside a response is denied — a row in a list, a relationship's counterpart, a merged record, a side of a match pair — it is dropped from the response, and the count reported alongside it drops too. Callers never receive a placeholder for something they may not see.

Access-control administration is exempt

Policies never gate the screens that manage policies, roles, groups, and permissions. A policy can restrict data; it can never make access control itself unmanageable.

5. Verify with a real account

Sign in as a user the policy targets — not as an administrator imagining it.

  • Confirm a record the policy denies is absent, rather than erroring.
  • Confirm the counts on that screen reflect the absence.
  • Confirm a record the policy does not cover is still reachable.
  • Confirm someone outside the targeted role is unaffected.
Test with the account, not the theory

A person holds the union of their roles. A policy targeting one of them applies regardless of what the others grant — that is deny-overrides — but which records they see also depends on permissions the policy says nothing about.

Next