Schemas
Cerbos policies rely on context data about the principal and the resource(s) that are submitted through the attr
fields of the API request. While the free-form nature of these fields gives you maximum flexibility to author policies that work on data of any shape or form, they can become difficult to reason about and make it harder to enforce system-wide standards and conventions.
Using the JSON Schema support built into Cerbos, you can define schemas for all your principal and resource attributes on a per-resource basis by specifying them in the resource policy. The Cerbos PDP will validate the incoming requests and either log warnings or completely reject them based on the schema enforcement configuration in effect.
Define schemas
Cerbos schemas are standard JSON Schemas (draft 2020-12). If you are using any of disk
, git
or blob
storage drivers the schemas are expected to be in a special directory named _schemas
located at the root of the storage directory or bucket. Use the Admin API to add or update schemas if you are using one of the database drivers.
To avoid repetition, you can define common schema fragments inline using $defs
or refer to other schemas using $ref
(see https://json-schema.org/understanding-json-schema/structuring.html). When using $ref
to refer to another schema stored in Cerbos storage, make sure to use an absolute URL with cerbos
as the scheme. For example, use cerbos:///common/address.json
to refer to a schema file stored in _schemas/common/address.json
(if using one of the disk-based stores). This ensures that policies remain portable between different environments.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"shipping_address": { "$ref": "cerbos:///address.json" },
"billing_address": { "$ref": "cerbos:///address.json" }
},
"required": ["first_name", "last_name", "shipping_address", "billing_address"]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
Validate requests using schemas
First, update your resource policy to point to the schemas that should be used to validate requests for that resource kind. For example, the following resource policy requires all requests for album:object
resource kind to be validated using principal.json
for the principal attributes and album/object.json
for the resource attributes respectively.
---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
importDerivedRoles:
- apatr_common_roles
resource: "album:object"
rules:
- actions: ['create']
effect: EFFECT_ALLOW
derivedRoles:
- owner
- actions: ['view']
effect: EFFECT_ALLOW
roles:
- user
condition:
match:
expr: request.resource.attr.public == true
schemas: (1)
principalSchema: (2)
ref: cerbos:///principal.json
resourceSchema: (3)
ref: cerbos:///album/object.json
ignoreWhen: (4)
actions: ['create', 'delete:*']
1 | Schema definition block. Optional. Leave this out if you do not want to use schema validation for this resource type. |
2 | Schema for validating the principal attributes. Optional. Leave this out if you do not want to validate the principal. |
3 | Schema for validating the resource attributes. Optional. Leave this out if you do not want to validate the resource. |
4 | Ignore block. Optional. Define the actions for which schema validation should be ignored. This is useful for special cases like CREATE where your resource might not have all the required attributes to pass schema validation. |
Finally, configure the schema enforcement level of the Cerbos PDP to either warn
or reject
and restart it. Now the PDP will validate any requests where the matching resource policy has schemas specified.
If enforcement level is |
{
"requestId": "test",
"resourceInstances": {
"XX125": {
"actions": {
"approve": "EFFECT_DENY",
"create": "EFFECT_DENY",
"defer": "EFFECT_ALLOW",
"view:public": "EFFECT_ALLOW"
},
"validationErrors": [
{
"path": "/department",
"message": "value must be one of \"marketing\", \"engineering\"",
"source": "SOURCE_PRINCIPAL"
},
{
"path": "/department",
"message": "value must be one of \"marketing\", \"engineering\"",
"source": "SOURCE_RESOURCE"
}
]
}
}
}