# Custom Policy Engine

In addition to access policies created as part of the [Dataset User Access Rules](/content/docs/datasets/#dataset-user-access-rules/index.html) experience, Satori also enables organizations to create additional fine-grained policies enforcing data access to Satori Datasets. The policy engine is the module that provides this functionality, which leverages user information, queries and the actual data returned from the data store to determine how access should be handled.

## How does the Custom Policy Engine Work?

The policy engine executes rules that are defined in the dataset custom policy tab. Rules are executed by priority, from the lowest to the highest priority number. A rule contains a boolean condition and an action. When the boolean condition evaluates to True, the action is taken.

_Note: all custom policy rules are evaluated prior to any standard access rules shown in the Satori UX._

## Actions

Actions determine how Satori should handle the query or result. Satori supports the following actions:

- `allow` \- instructs the policy engine to stop processing the next rules and allow the query or result to be sent to the data store or client, respectively.
- `alert` \- instructs the policy engine to generate an incident in audit log of the management console for this query or result.
- `mask` \- instructs the policy engine to apply a transformation on the data before it’s returned to the client. For more information about masking see [Dynamic Masking](/content/docs/dynamic-masking/index.html).
- `block` \- instructs the policy engine to stop processing the next rules and block the query or result, returning an error message to client.

## Tags

Conditions are composed of tags that represent the existence of various aspects of the data access. For example, the tag `identity.principal.name::john@example.com` will be available when `john@example.com` is connected to the data store.

Satori separates tags into two categories, data tags and identity tags. Data tags provide information about properties of the data, for example, if a particular type of PII data type appears in the data. Identity tags provide information about properties of the user, for example, if the user is assigned with a particular role.

Satori provides a large number of built-in tags and customers can also define their own tags by using Satori-provided [matchers](/content/docs/acl/matchers/index.html). For a list of all available tags, please refer to the [tag reference](/content/docs/acl/tags/index.html).

To understand the relationship between rules and tags, examine the following screenshot. In this configuration, on the right hand side, a data tag named _financial_data_ is created, and its purpose is to match on various database schemas. This tag is then referenced in the rule named _AlertWhenPostgresDB_IsQueried_ on the left hand side:

## Conditions

Conditions are a conjunction of the tags they contain. For a condition to evaluate to True, all tags must exist. The negation of a tag is supported by using the NOT keyword before the tag itself. See the Rule Language section for more information.

## Rule Language

Rules are defined in [YAML](https://yaml.org/) and maintained in the Custom Policy tab of each Satori Dataset in the management console. The general format is:

```
rules:
  - name: "Rule display name"
    priority: <0..n>
    action: <allow|alert|block>
    apply_and_continue: <true|false>
    data_tags:
      - [NOT] <data_tag>
    ...
      - [NOT] <data_tag>
    identity_tags:
      - [NOT] <identity_tag>
    ...
      - [NOT] <identity_tag>
  - name: "Rule display name"
      ...
```

## Apply and Continue

Policy execution is stopped once a rule is matched. The policy execution can be forced to continue evaluating lower priority rules by enabling the `apply_and_continue` attribute. In which case that policy engine will apply the action and continue to evaluate the next rules.

All custom policies are evaluated prior to any standard access policies on the User Access Rules tab of a Dataset. Thus, if `apply_and_continue` is set to `false` and a custom rule is triggered, then no standard User Access Rules will be triggered.

`apply_and_continue` is not applicable for rules with `block` or `allow` actions. By definition, if `block` or `allow` is the evaluated result, then no other filtering or evaluations should occur.

In case of policy conflicts the following will apply:

- In case a `block` action is triggered, blocked will be applied, any previous actions will be disregarded.
- In case a `allow` action is triggered, allow will be applied, any previous actions will be applied.
- In case of multiple masking profiles being triggered they will all be applied, in the case of a conflict (i.e different actions on the same data type) the rule with the higher priority will be applied.

In the following example, a user with the Snowflake analyst role accessing a table containing PII will trigger both policies (alert rule has the `apply_and_continue: true` flag set):

```
rules:
  - name: "Alert on access to email addresses"
    action: alert
    data_tags:
      - c12n.pii::email
    priority: 0
    apply_and_continue: true
  - name: Mask Customer PII for Analysts
    action:
      type: mask
      profile: 7d1c1d8f-2fed-4897-8163-ef174d885192
    identity_tags:
      - identity.datastore.role::analyst
    data_tags:
      - c12n.pii
    priority: 1
```

## Custom Tags

Customers can create their own tags in the Tags section of the dataset custom policy view in the management console. These tags are built using [Matchers](/content/docs/acl/matchers/index.html), which are re-usable modules that Satori provides. `matcher_id`'s are reserved keywords in the Satori platform and perform specific matching functionality.

```
tags:
  - display_name: "Tag display name"
    tag: <tag string to use in rule>
    matcher_id: <matcher to use for this tag>
    matcher_data:
      ...
  ...
  - display_name: "Tag display name"
    ...
```

Note: Any tag types contains white spaces must be quoted.

## Examples

### Allow all traffic

```
rules:
  - name: "Allow all"
    priority: 0
    action: allow
```

### Block all traffic

```
rules:
  - name: "Block all"
    priority: 0
    action: block
```

### Alert on access to email addresses

```
rules:
  - name: "Alert on access to email addresses"
    action: alert
    data_tags:
      - c12n.pii::email
    priority: 0
```

### Alert on access by a custom tag with spaces

```
rules:
  - name: "Alert on matching by custom category"
    action: alert
    data_tags:
      - "'c12_custom.my custom category::my custom classifier'"
    priority: 0
```

### Block access to passwords except for administrators in Snowflake

```
rules:
  - name: "Only admins can access passwords"
    action: block
    data_tags:
      - c12n.operational::password
    identity_tags:
      - "NOT identity.datastore.role::accountadmin"
    priority: 0
```

### Block access to any wildcard queries

In the following example, "select * from" will be blocked for two specific tables, 'people_v2' and 'customer_purchases'. Reminder, the matcher_id `wildcard_tables` is a reserved keyword in Satori and a Satori [Matcher](/content/docs/acl/matchers/index.html).

```
rules:
  - name: WildcardBlocked
    action: block
    priority: 0
    data_tags:
    - wildcard_query
    apply_and_continue: true

tags:
  - display_name: "Detect wildcard queries on sensitive tables"
    tag: "wildcard_query"
    matcher_id: wildcard_tables
    matcher_data:
     match:
      - table: people_v2
      - table: customer_purchases
```

### Block access to any query if custom tags are found

In the following example, the query is blocked if the specific custom tag/classifier 'BLOCKER' is discovered in the query.

First, we create a new classifier in a custom category. Then, we associate this tag with some of our data:

Finally, the following custom policy will block any queries where this tag is discovered:

```
rules:
  - name: BLOCKED
    action: block
    priority: 0
    data_tags:
      - c12n_custom.BLOCKS::BLOCKER
    apply_and_continue: true
```

### Only allow the finance team access certain database objects

```
rules:
  - name: "Financial data access"
    action: block
    identity_tags:
      - "NOT identity.idp.group::Finance"
    data_tags:
      - financial_data
    priority: 0

tags:
  - display_name: "Finance Tables"
    tag: financial_data
    matcher_id: table_name
    matcher_data:
      match:
        # All tables named deals in every schema or database
        - deals
        # All tables named quotes in the public schema of every database
        - public.quotes
        # The assets table in the restricted schema in the finance database
        - finance.restricted.assets
```
