Best Practices

Policy Design

Writing policies that are auditable, testable, and understandable.

A good policy is one that, a year from now, someone who didn't write it can read, understand, and predict the behavior of. Most bad policies fail that test. They started narrow, grew with exceptions, and now exist as a tangle that only the original author remembers.

Principles

One policy per clear governance rule. If you can describe what a policy does in a single sentence, it's probably the right size. If you need a paragraph, it's two policies stapled together.

Positive policies for access; negative policies for carve-outs. The tenant's default is deny. Allow policies grant access under conditions; deny policies override allows for specific exclusions (legal hold, executive exclusion, jurisdictional freeze). Don't use one to do the work of the other.

Reference the schema, not specific values. A policy that says "sensitivity at least confidential" survives the addition of a new sensitivity tier. A policy that enumerates specific values breaks on schema evolution.

Obligations attach behavior, not access. "Access is allowed for these principals, and the view must be watermarked" is an allow-plus-obligation. Don't model obligations as access conditions; they belong on the allow.

Write the rationale. Every policy gets a human-readable description. When a policy denies someone, the description is what makes the decision explainable. When the policy is reviewed next year, the description is what lets the reviewer understand why it exists.

Patterns

The baseline-and-exceptions pattern

Most organizations have a small number of broad rules and a larger number of narrow exceptions:

  • Baseline allow: Internal data is readable by all members.
  • Baseline allow: Confidential data is readable by members with clearance level 2 or higher.
  • Baseline allow: Restricted data is readable by members with clearance level 3 or higher, from approved network zones.
  • Exception deny: Legal hold set LH-2026-01 is accessible only to the litigation response team.
  • Exception deny: Data tagged with executive-excluded is inaccessible to members below executive tier.

The baseline allows are few and simple. The exceptions are narrow and individually understandable. The combined behavior is predictable.

The origin-bounded pattern

For data that should not leave its origin boundary:

  • Allow: Customer-A data is accessible to Customer-A's workspace members only.
  • Allow: Customer-B data is accessible to Customer-B's workspace members only.
  • (Parameterized in a single policy with a scope predicate, not as N separate policies.)

The key is parameterization. Don't write one policy per customer — write a single policy that takes the customer identity as a parameter and enforces the invariant that workspace membership and data origin must match.

The time-bounded release pattern

For data that should become accessible only after a specific date (embargoed announcements, earnings releases, coordinated disclosures):

  • Allow: Object tagged with release-at: <timestamp> is accessible after the timestamp.
  • Obligation: Before the timestamp, denied with rationale embargo-active.

This is policy logic, not scheduling. The object becomes accessible on the policy re-evaluation after the timestamp passes; nothing has to run at the exact moment.

Testing

Every tenant should maintain a sample evaluation set — a corpus of (principal, object, context) triples with the expected decision and rationale. Every policy change runs against the sample set before publication. When a policy change produces a different decision than expected on a sample, either the sample is wrong (and needs updating) or the policy is wrong (and needs fixing).

A realistic sample set includes:

  • Typical principals: a standard employee, a senior manager, an external contractor.
  • Edge-case principals: a user with lapsed clearance, a just-onboarded user, a service account, a coalition partner.
  • Typical objects: one per classification tier in each business domain.
  • Edge-case objects: a freshly classified object, an object with deprecated tags, a legal-hold object.
  • Typical contexts: in-region weekday business hours, out-of-region, off-hours.

Maintain the sample set like code. Review it quarterly to add new edge cases that came up in production.

What good policies don't do

They don't try to be Turing-complete. If a policy needs loops, complex data lookups, or stateful behavior, the underlying requirement probably belongs in a dedicated application rather than in the access policy.

They don't embed credentials. A policy never contains secrets. It references attributes; the attributes come from identity claims or object tags.

They don't make destination-system assumptions. A policy protecting a data object shouldn't assume a specific consuming application. The object might be accessed from ten different applications; the policy applies equally to all of them.

They don't silently change behavior. Every policy publish is a ledger event. Every decision is logged. A production policy that does something surprising is discoverable; a local override that does something surprising is not.

Living with policies long-term

Review policies quarterly. Any policy that hasn't been evaluated in three months is a candidate for retirement. Any policy whose denials consistently surprise the affected principals needs a rationale improvement or a redesign.

Measure denial rates per policy. High denial rates can mean either that the policy is doing its job (denying unauthorized access) or that the policy is miscalibrated (denying legitimate access). Distinguishing the two requires investigating the specific principals affected.

Retire policies proactively. A policy that covered a specific project that has ended should be explicitly retired, not left as legacy clutter. Every active policy is cognitive overhead for the team that reviews them.

Keeping the active policy set small and well-understood is the single best predictor of a healthy rollout over years.