> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/pbac/create-a-policy.md).

# Create a policy

Create a policy header, author its first version with the form builder or the Cedar editor, and manage the version history without changing what is in force.

## What this is, and when you need it

Authoring a rule that decides requests on attributes rather than on membership. The worked case: a contractor should reach an application only during working hours.

This page gets you to a saved, compiling `DRAFT`. It deliberately stops there — activating it is [Roll a policy out safely](/administration-guide/pbac/roll-out-a-policy.md), and you should [simulate](/administration-guide/pbac/simulate-a-policy.md) it before you go anywhere near that.

## At a glance

|                          |                                                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| **You will end up with** | A `DRAFT` policy with one compiling version, governing nothing yet                                                        |
| **Where**                | **Administration → PBAC Policies** → **Policy Library** and **Policy Editor**                                             |
| **You need first**       | The rule stated in words, the entity types it is about, and any access right it names already existing in your deployment |
| **Takes**                | 15–30 minutes for a first policy                                                                                          |
| **Reversible**           | Yes, entirely — a `DRAFT` is never evaluated. Deleting the policy later is not reversible                                 |

## Before you begin

* **State the rule in one sentence first**, including what happens to everyone it does *not* match. A policy that permits contractors during working hours says nothing about employees, and Cedar's default-deny means "says nothing" and "denies" are the same thing unless another policy permits them.
* **The access rights you intend to name must already exist.** The builder only offers what the server declares, so a right you have not created is not selectable.
* **Read** [**The policy model**](/administration-guide/pbac/policy-model.md)**.** The attribute-guard rule in particular.

## Create the policy header

{% stepper %}
{% step %}

### Open the library and start a new policy

**Administration → PBAC Policies** opens on **Policy Library**, which lists every policy in every lifecycle state — drafts being authored, active policies being enforced, and deprecated ones kept for reference. Search filters by name; the **View** menu controls which columns show.

The **Mode** column is worth learning to read: it shows `SHADOW`, `FULL`, or `PARTIAL` with its percentage (*PARTIAL 25%*). **A dash means no mode is recorded — and that policy is enforced as though it were `FULL` once it is `ACTIVE`.**

Click **New Policy**.
{% endstep %}

{% step %}

### Fill in the header and save before authoring

Name, description, lifecycle status — a new policy defaults to `DRAFT` — and optionally an enforcement mode, which does nothing until the policy is `ACTIVE`.

The version authoring card is **locked** at this point. That is not a fault: versions can only be appended to a policy that exists, so the header has to be saved first. Click **Save**, and the editor reopens in edit mode with the card unlocked.
{% endstep %}

{% step %}

### Author the first version

The authoring card offers two views of the same policy behind a **Form / Cedar text** toggle. **The Cedar text is what gets saved**; the form writes through to it on every edit.

Use the form unless the policy needs something it cannot express — see [What the form builder can and cannot express](/administration-guide/pbac/policy-model.md#what-the-form-builder-can-and-cannot-express). It picks everything except literal values from the vocabulary the server declares, so it cannot produce a policy naming something the decision engine could not resolve.

| Field          | What it sets                                                                                                                                                                                 |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Effect**     | `permit` or `forbid`                                                                                                                                                                         |
| **Principal**  | Who the policy is about — the user type, optionally narrowed to one user, or to members of a group, role or organization (**Belongs to**)                                                    |
| **Action**     | Which access rights it covers. Leave empty to cover any action. Cedar cannot restrict the action in a policy head, so a chosen right is written as a **condition** rather than into the head |
| **Resource**   | What the policy is about — a resource, group, role, organization or user, optionally narrowed to one entity or an ancestor                                                                   |
| **Conditions** | An **OR of AND-groups**: the policy applies when *any* group matches, and a group matches when *all* its rows do                                                                             |

Condition rows test attributes of the principal, the resource, or the request context. Enumerable context values are shown as labels — hours as *9 AM*, weekdays as *Friday* — while the stored policy text holds the underlying number. The operators offered depend on the attribute's type.

The **Generated Cedar** panel below the form shows exactly what is being produced. Read it before saving; it is the artefact, and the form is only a way of typing it.
{% endstep %}

{% step %}

### Save, and let the compiler check it

Cedar text is compiled server-side on save. A version that does not compile is **rejected at save time** with the compiler's own error message, so a policy that could never be activated is never stored.

Each version records its priority, an optional change comment, the author and the time.

| Field              | Description                                                                                        |
| ------------------ | -------------------------------------------------------------------------------------------------- |
| **Priority**       | Orders policies when the engine reports which determined a decision; lower wins. Defaults to `500` |
| **Change comment** | Free text, shown in the version history. The only place to record *why* — use it                   |
| {% endstep %}      |                                                                                                    |
| {% endstepper %}   |                                                                                                    |

## The Cedar text editor

The **Cedar text** tab is a full editor with syntax highlighting and context-aware autocompletion: entity types after `::`, attributes after `principal.`, `resource.` and `context.` — based on the entity types pinned in the policy head — and concrete access rights after `action ==`.

A policy the form would generate for the worked case:

{% code overflow="wrap" %}

```
permit(
    principal is Openiam::User::Human,
    action,
    resource is Openiam::Group
)
when {
    (principal has employeeTypeId && principal.employeeTypeId == "CONTRACTOR"
     && context.timeOfDay >= 9 && context.timeOfDay < 17
     && context.dayOfWeek <= 5)
};
```

{% endcode %}

Note the `principal has employeeTypeId` guard, and that `timeOfDay` is UTC — both explained in [The policy model](/administration-guide/pbac/policy-model.md).

## Versions, and what changes what

{% hint style="warning" %}
**Appending a version does not deploy it.** Every save of changed text creates a new immutable version and leaves the *current* pointer where it was. To put a different version into force — including rolling back to an older one — select it in the version history and click **Make current**. That explicit step is the only thing that moves the pointer.

The practical consequence: editing a live policy is safe by default. You can author and save a fix against an `ACTIVE` policy without it taking effect, then make it current when you are ready.
{% endhint %}

## Verification

| What to check                    | How                                                                                                 |
| -------------------------------- | --------------------------------------------------------------------------------------------------- |
| The version saved                | It appears as a chip in the version history, with your author name and timestamp                    |
| It compiles                      | It saved at all — a version that does not compile is rejected and never stored                      |
| It says what you meant           | Select the chip and read the Cedar text back, not the form                                          |
| It is not yet governing anything | Status reads `DRAFT` in the library, and the **Mode** column is irrelevant while it does            |
| It decides correctly             | [Simulate it](/administration-guide/pbac/simulate-a-policy.md) against real users before activating |

## When it goes wrong

| Symptom                                                | Cause                                                                                    | Fix                                                                                                    |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| The version card is locked and will not accept text    | The policy header has not been saved yet                                                 | Save the header; the card unlocks in edit mode                                                         |
| Save is refused with a compiler message                | The Cedar does not compile. This is the intended behaviour, not a defect                 | Fix what the message names. Nothing was stored, so there is nothing to roll back                       |
| The Form tab says it cannot show this policy           | The version uses `unless`, several statements, or nesting deeper than the builder covers | Expected. Continue on the Cedar text tab; the form is not lossy, it declines rather than approximating |
| A condition on an attribute never matches              | The attribute is absent on those users and the read errors rather than returning false   | Guard it: `principal has <attr> && principal.<attr> == …`                                              |
| A condition on a custom attribute never matches        | Tags are **lists**, so `==` cannot match                                                 | `principal.getTag("x").contains("y")`                                                                  |
| An access right you need is not in the **Action** list | It does not exist in this deployment; the builder only offers what the server declares   | Create the access right first — [The access model](/administration-guide/access/access-model.md)       |
| You edited a live policy and nothing changed           | Expected. Appending a version never moves the current pointer                            | Select the version and **Make current**                                                                |

## Roll it back

A `DRAFT` needs no rollback — it governs nothing. For a policy already in force, **Make current** on the previous version is the rollback, and it is a normal operation rather than an emergency one.

Deleting a policy is different: it removes the header **and every version**, and cannot be undone. The console asks for confirmation. Completed simulation runs survive — they reference the version by identifier and stay readable — as do the usage counters recorded for billing.

## Related

* [The policy model](/administration-guide/pbac/policy-model.md) — the entities, attributes and guard rules this page applies
* [Simulate a policy](/administration-guide/pbac/simulate-a-policy.md) — do this before activating
* [Roll a policy out safely](/administration-guide/pbac/roll-out-a-policy.md) — what happens when you set the status to `ACTIVE`
* [PBAC reference](/administration-guide/pbac/pbac-reference.md) — the REST API behind these screens

*Applies to OpenIAM 2026.8.1. Last reviewed 13 August 2026.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/pbac/create-a-policy.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
