Conditions
A powerful feature of Cerbos policies is the ability to define conditions that are evaluated against the data provided in the request. Conditions are written using the Common Expression Language (CEL).
Cerbos ships with an interactive REPL that can be used to experiment with writing CEL conditions. It can be started by running cerbos repl . See the REPL documentation for more information.
|
condition:
match:
all:
of:
- expr: request.resource.attr.status == "PENDING_APPROVAL"
- expr: "GB" in request.resource.attr.geographies
Within a condition block you have access to serveral special variables:
request
-
The entire request object containing data provided about the resource and the principal. Use dots to access nested fields. For example, the expression to get the principal’s department attribute is
request.principal.attr.department
. variables
-
Access variables declared in the
variables
section of the policy. P
-
An alias for
request.principal
for accessing the principal object. R
-
An alias for
request.resource
for accessing the resource object. V
-
An alias for
variables
for accessing the policy variables object.
Every condition expression must evaluate to a boolean true/false value. You can combine complex expressions together in a single condition block by using the all
, any
, or none
operators.
condition:
match:
expr: matches(P.id, "^dev_.*")
all
operator: all expressions must evaluate to true (logical AND)condition:
match:
all:
of:
- expr: R.attr.status == "PENDING_APPROVAL"
- expr: "GB" in R.attr.geographies
- expr: P.attr.geography == "GB"
any
operator: only one of the expressions has to evaluate to true (logical OR)condition:
match:
any:
of:
- expr: R.attr.status == "PENDING_APPROVAL"
- expr: "GB" in R.attr.geographies
- expr: P.attr.geography == "GB"
none
operator: none of the expressions should evaluate to true (logical negation)condition:
match:
none:
of:
- expr: R.attr.status == "PENDING_APPROVAL"
- expr: "GB" in R.attr.geographies
- expr: P.attr.geography == "GB"
condition:
match:
all:
of:
- expr: R.attr.status == "DRAFT"
- any:
of:
- expr: R.attr.dev == true
- expr: matches(R.attr.id, "^[98][0-9]+")
- none:
of:
- expr: R.attr.qa == true
- expr: R.attr.canary == true
The above nested block is equivalent to the following:
condition:
match:
expr: |-
(R.attr.status == "DRAFT" &&
(R.attr.dev == true || matches(R.attr.id, "^[98][0-9]+")) &&
!(R.attr.qa == true || R.attr.canary == true))
Policy variables
If your policy repeats the same expression in multiple conditions, you can declare it in the variables section of a policy and refer in the conditions to avoid a repeat.
---
apiVersion: "api.cerbos.dev/v1"
variables:
is_dev_record: request.resource.attr.dev_record == true
principalPolicy:
principal: daffy_duck
version: "dev"
rules:
- resource: leave_request
actions:
- name: dev_record_wildcard
action: "*"
condition:
match:
expr: variables.is_dev_record
effect: EFFECT_ALLOW
- resource: employee_profile
actions:
- name: view_employee_profile
action: "*"
condition:
match:
all:
of:
- expr: V.is_dev_record
- expr: request.resource.attr.public == true
effect: EFFECT_ALLOW
- resource: salary_record
actions:
- action: "*"
effect: EFFECT_DENY
Auxiliary Data
If you have auxiliary data sources configured, they can be accessed using request.aux_data
.
"cerbie" in request.aux_data.jwt.aud && request.aux_data.jwt.iss == "cerbos"
Operators
CEL has many builtin functions and operators. The fully up-to-date list can be found at https://github.com/google/cel-spec/blob/master/doc/langdef.md#list-of-standard-definitions. |
Operator | Description |
---|---|
|
Logical negation (NOT) |
|
Subtraction/numeric negation |
|
Unequals |
|
Modulo |
|
Logical AND |
|
Logical OR |
|
Multiplication |
|
Addition/concatenation |
|
Division |
|
Less than or equal to |
|
Less than |
|
Equals |
|
Greater than or equal to |
|
Greater than |
|
Membership in lists or maps |
Durations
...
"resource": {
"kind": "leave_request",
"attr": {
"cooldownPeriod": "3750s",
"lastAccessed": "2021-04-20T10:00:20.021-05:00"
}
}
...
Function | Description | Example |
---|---|---|
|
Convert a string to a duration. The string must contain a valid duration suffixed by one of |
|
|
Get hours from a duration |
|
|
Get milliseconds from a duration |
|
|
Get minutes from a duration |
|
|
Get seconds from a duration |
|
|
Time elapsed since the given timestamp to current time on the server. This is a Cerbos extension to CEL |
|
Hierarchies
The hierarchy functions are Cerbos-specific extensions to CEL. |
...
"principal": {
"id": "john",
"roles": ["employee"],
"attr": {
"scope": "foo.bar.baz.qux",
}
},
"resource": {
"kind": "leave_request",
"attr": {
"scope": "foo.bar",
}
}
...
Function | Description | Example |
---|---|---|
|
Convert a dotted string or a string list to a hierarchy |
|
|
Convert a delimited string representation to a hierarchy |
|
|
Returns true if the first hierarchy shares a common prefix with the second hierarchy |
|
|
Returns the common ancestor hierarchy |
|
|
Mirror function of |
|
|
Returns true if the first hierarchy is a first-level child of the second hierarchy |
|
|
Mirror function of |
|
|
Returns true if one of the hierarchies is a prefix of the other |
|
|
Returns true if both hierarchies share the same parent |
|
|
Returns the number of levels in the hierarchy |
|
|
Access a level in the hierarchy |
|
IP Addresses
The IP address functions are Cerbos-specific extensions to CEL. |
...
"principal": {
"id": "elmer_fudd",
"attr": {
"ipv4Address": "192.168.0.10",
"ipv6Address": "2001:0db8:0000:0000:0000:0000:1000:0000"
}
}
...
Function | Description | Example |
---|---|---|
|
Check whether the IP address is in the range defined by the CIDR |
|
Lists and maps
...
"principal": {
"id": "elmer_fudd",
"attr": {
"id": "125",
"teams": ["design", "communications", "product", "commercial"],
"clients": {
"acme": {"active": true},
"bb inc": {"active": true}
}
}
}
...
Operator/Function | Description | Example |
---|---|---|
|
Concatenates lists |
|
|
Index into a list or a map |
|
|
Check whether all elements in a list match the predicate |
|
|
Produces the set difference of two lists |
|
|
Check whether at least one element matching the predicate exists |
|
|
Check that only one element matching the predicate exists |
|
|
Filter a list using the predicate |
|
|
Checks whether the lists have at least one common element |
|
|
Check whether the given element is contained in the list or map |
|
|
Produces the set intersection of two lists |
|
|
Checks whether the list is a subset of another list |
|
|
Transform each element in a list |
|
|
Number of elements in a list or map |
|
Strings
...
"resource": {
"kind": "leave_request",
"attr": {
"id": "125",
"department": "marketing"
}
}
...
Function | Description | Example |
---|---|---|
|
Encode as base64 |
|
|
Decode base64 |
|
|
Get the character at given index |
|
|
Check whether a string contains the given substring |
|
|
Check whether a string has the given suffix |
|
|
Index of the first occurrence of the given character |
|
|
Index of the last occurrence of the given character |
|
|
Convert ASCII characters to lowercase |
|
|
Check whether a string matches a RE2 regular expression |
|
|
Replace all occurrences of a substring |
|
|
Replace with limits. Limit 0 replaces nothing, -1 replaces all. |
|
|
Get the length of the string |
|
|
Split a string using a delimiter |
|
|
Split a string with limits. Limit 0 returns an empty list, 1 returns a list containing the original string. |
|
|
Check whether a string has the given prefix |
|
|
Selects a substring from the string |
|
|
Remove whitespace from beginning and end |
|
|
Convert ASCII characters to uppercase |
|
Timestamps
...
"resource": {
"kind": "leave_request",
"attr": {
"lastAccessed": "2021-04-20T10:00:20.021-05:00",
"lastUpdateTime": "2021-05-01T13:34:12.024Z",
}
}
...
Function | Description | Example |
---|---|---|
|
Convert an RFC3339 formatted string to a timestamp |
|
|
Get day of month from a timestamp |
|
|
Get day of month from a timestamp. Returns a zero-based value |
|
|
Get day of week from a timestamp. Returns a zero-based value where Sunday is 0 |
|
|
Get day of year from a timestamp. Returns a zero-based value |
|
|
Get full year from a timestamp |
|
|
Get hours from a timestamp |
|
|
Get milliseconds from a timestamp |
|
|
Get minutes from a timestamp |
|
|
Get month from a timestamp. Returns a zero-based value where January is 0 |
|
|
Get seconds from a timestamp |
|
|
Current time on the server. This is a Cerbos extension to CEL |
|
|
Time elapsed since the given timestamp to current time on the server. This is a Cerbos extension to CEL |
|
timestamp(R.attr.lastUpdateTime) - timestamp(R.attr.lastAccessed) > duration("36h")
timestamp(R.attr.lastUpdateTime) + duration("24h") == timestamp("2021-05-02T13:34:12.024Z")