Attribute schema

The policies for this section can be found on Github.

An additional check bit of business logic has been introduced for the contact resource which requires the active attribute of a contact to be set to True to be able to update or delete it. This is so that old contacts are kept for reporting purposes and can't be accidentally deleted or updated.

This now means there are two attributes of a contact resource that are now required for the policies to be computed - ownerId and active. If either of these is not included in the request to check permissions the result would not be as expected (defaulting to EFFECT_DENY).

To prevent this mistake, it is possible to define a schema for the attributes of a principal and resources which Cerbos validates against at request time to ensure all fields are provided as expected.

Defining schema

Atrribute schema are defined in JSON Schema (draft 2020-12) and stored in a special _schemas sub-directory along side the policies

For the contact resource the schema looks like the following:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ownerId": { "type": "string" },
    "active": { "type": "boolean" }
  },
  "required": ["ownerId", "active"]
}

Once defined, it is then linked to the resource via adding a reference in the policy:

---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  version: "default"
  resource: "contact"
  importDerivedRoles:
    - cerbforce_derived_roles
  rules:
    - actions:
        - create
        - read
      effect: EFFECT_ALLOW
      roles:
        - user

    - actions:
        - update
        - delete
      effect: EFFECT_ALLOW
      derivedRoles:
        - owner
      condition:
        match:
          expr: request.resource.attr.active == true

    - actions:
        - "*"
      effect: EFFECT_ALLOW
      roles:
        - admin
  schemas:
    resourceSchema:
      ref: cerbos:///contact.json

The same can be done with attributes of a principal - you can find out more in the documentation.

Enforcing schema

Validating the request against the schema is done at request time by the server - to enable this a new schema configuration block needs adding to the config.yaml.

---
server:
  httpListenAddr: ":3592"
storage:
  driver: "disk"
  disk:
    directory: /tutorial/policies
schema:
  enforcement: reject

With this now in place, any request that is made to check authorization of a contact resource is rejected if the attributes are not provided or of the wrong type:

Request

{
  "principal": {
    "id": "user_1",
    "roles": ["user"],
    "attr": {}
  },
  "resource": {
    "kind": "contact",
    "instances": {
      "contact_1": {
        "attr": {
          "ownerId": "user1"
        }
      }
    }
  },
  "actions": ["read"]
}

Response

{
  "resourceInstances": {
    "contact_1": {
      "actions": {
        "read": "EFFECT_DENY"
      },
      "validationErrors": [
        {
          "message": "missing properties: 'active'",
          "source": "SOURCE_RESOURCE"
        }
      ]
    }
  }
}