# Scoped policies

|     |     |
| --- | --- |
|  | This documentation is for<br>an as-yet unreleased<br>version of Cerbos PDP. Choose 0.53.0 from the version picker at the top right or navigate to [https://docs.cerbos.dev](https://docs.cerbos.dev/) for the latest version. |

|     |     |
| --- | --- |
|  | Scoped Policies are optional and are only evaluated if a "scope" is passed in the request, and there are matching "scope" attributes defined in the policies. |

|     |     |
| --- | --- |
|  | Empty scope can also be represented by setting the "scope" to value "." in the request. |

|     |     |
| --- | --- |
|  | Resource and principal policies can define "scopePermissions", which affects how rules are applied across scopes. See the [scope permissions documentation](https://docs.cerbos.dev/cerbos/prerelease/policies/scope_permissions) for more details. |

Scoped policies offer a way to model hierarchical relationships that regularly occur in many situations. Typically, the requirement is to have a base set of policies that can then be overridden for specific cases. For example, a multi-tenant SaaS system could have a standard set of access rules that can then be customised to suit the requirements of different tenants. Another example is a large organization that might want to have regional or departmental customisations to their global access rules.

Cerbos resource and principal policies have an optional `scope` field that can be used to indicate that they are part of a set of policies that must be evaluated together. Additionally, resource and principal policies within the same scope must use the same `scopePermissions` setting to define how rules interact across scope levels.

```yaml
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  version: "default"
  scope: "acme.corp" (1)
  scopePermissions: SCOPE_PERMISSIONS_OVERRIDE_PARENT (2)
  resource: "album:object"
  rules:
    - actions: ['*']
      effect: EFFECT_ALLOW
      roles: ["admin"]
```

|     |     |
| --- | --- |
| **1** | Scope definition |
| **2** | Scope permissions setting |

The value of `scope` is a dot-separated string where each dotted segment defines an ancestor. During policy evaluation, the Cerbos engine starts with the most specific scoped policy and moves up the hierarchy.  
NOTE: The value of the `scopePermissions` field affects the policy evaluation behaviour. See [scope permissions](https://docs.cerbos.dev/cerbos/prerelease/policies/scope_permissions) for more information.  
For example, consider a policy with the scope `a.b.c`. The Cerbos engine could process up to four policies to arrive at the final decision:

- scope `a.b.c`
- scope `a.b`
- scope `a`
- scope `` (no scope)

To illustrate, consider the following Check request:

```json
{
  "requestId":  "test01",
  "actions":  ["view", "comment"],
  "resource":  {
    "kind":  "album:object",
    "policyVersion": "default",
    "scope": "customer.abc", (1)
    "instances": {
      "XX125": {
        "attr":  {
          "owner":  "alicia",
          "public": false,
          "tags": ["x", "y"],
        }
      }
    }
  },
  "principal":  {
    "id":  "alicia",
    "policyVersion": "default",
    "scope": "customer", (2)
    "roles":  ["user"],
    "attr": {
      "geography": "GB"
    }
  }
}
```

|     |     |
| --- | --- |
| **1** | Optional resource scope |
| **2** | Optional principal scope |

When processing the above request, the decision flow chart for the Cerbos engine would look like the following:

## Working with scoped policies

- The policy without any scope defined is always the base policy. It is used by default if a request does not specify any scope.

- Scope permissions must be consistent within the same scope. If conflicting `scopePermissions` settings are detected in policies within a shared scope, a build-time error will occur.

- Scope traversal behaviour depends on `scopePermissions`:

- With `SCOPE_PERMISSIONS_OVERRIDE_PARENT`, the first policy to return a decision wins for each action.

- With `SCOPE_PERMISSIONS_REQUIRE_PARENTAL_CONSENT_FOR_ALLOWS`, leaf nodes can only **restrict** access and must conform to parent permissions.

- There must be no gaps in the policy chain. For example, if you define a policy with scope `a.b.c`, then policies with scopes `a.b`, `a`, and no-scope should also exist in the policy repository.

- [Schemas](https://docs.cerbos.dev/cerbos/prerelease/policies/schemas) must be the same among all the policies in the chain. The schemas used to validate the request are taken from the base policy (policy without a scope). Schemas defined in other policies of the chain will be ignored.

- First match wins (when using `SCOPE_PERMISSIONS_OVERRIDE_PARENT`): Scoped policies are evaluated from the most specific to the least specific. The first policy to produce a decision (ALLOW/DENY) for an action is the winner. The remaining policies cannot override the decision for that particular action.

- Parent constraints apply (when using `SCOPE_PERMISSIONS_REQUIRE_PARENTAL_CONSENT_FOR_ALLOWS`): The most specific policies can only **restrict permissions** further, not grant new ones.

- **Explicit imports for derived roles and variables**: Variables and derived roles imports are not inherited between policies. Explicitly import any derived roles and re-define any variables in each policy that requires them.

- Unless [lenient scope search](https://docs.cerbos.dev/cerbos/prerelease/configuration/engine#lenient_scopes) is enabled, a policy file matching the exact scope requested in the API request must exist in the store.
