Adding conditions

The policies for this section can be found on Github.

In the previous section, an RBAC policy was created that allowed anyone with a user role to update a user resource - this isn't what is intended as it would allow users to update other users' profiles.

--- apiVersion: api.cerbos.dev/v1 resourcePolicy: version: "default" resource: "user" rules: - actions: - create - read - update effect: EFFECT_ALLOW roles: - user # ....other conditions

This blanket approach is where using pure role-based access controls falls down as there is more nuanced required to meet the requirements.

Conditions

Cerbos is a powerful Attribute-based Access Control system that can make contextual decisions at request time whether an action can be taken.

In this scenario, Cerbforce's business logic states that a user can only update their own user profile. To implement this a check needs to be made to ensure the ID of the user making the request matches the ID of the user resource being updated.

Conditions in Cerbos are written in Common Expression Language (CEL) which is a simple way of defining boolean logic of conditions. In this environment, there are two main bits of data provided that are of interest request.principal which is the information about the user making the request and request.resource which is the information about the resource being accessed.

The data model for each of these is as follows:

// request.principal { "id": "somePrinicpalId", // the prinicpal ID "roles": ["user"], // the list of roles from the auth provider "attr": { // a map of attributes about the prinicpal } } // request.resource { "id": "someResourceId", // the resource ID "attr": { // a map of attributes about the resourece } }

Using this information a check to see if the principal ID is the same as the ID of the user resource being accessed can be defined as

request.resource.id == request.principal.id

Adding this to the policy request a new rule to be created that is just for the update and delete actions which are for the user role and has a single condition.

--- apiVersion: api.cerbos.dev/v1 resourcePolicy: version: "default" resource: "user" rules: - actions: - create - read effect: EFFECT_ALLOW roles: - user - actions: - update - delete effect: EFFECT_ALLOW roles: - user condition: match: expr: request.resource.id == request.principal.id # ....other conditions

Complex logic can be defined in conditions (or sets of conditions) which you can read more about in the docs.

Extending tests

Now that you have a conditional policy, you can add these as test cases in the user tests. You can now define multiple user resources and principals and create test cases for ensuring the update action is allowed when the ID of the principal matches the ID of the resource, as well as checking that it isn't allowed if the condition is not met.

--- name: UserTestSuite description: Tests for verifying the user resource policy principals: admin: id: admin roles: - admin user1: id: user1 roles: - user user2: id: user2 roles: - user resources: admin: kind: user id: admin user1: kind: user id: user1 user2: kind: user id: user2 tests: - name: User CRUD Actions input: principals: - admin - user1 - user2 resources: - admin - user1 - user2 actions: - create - read - update - delete expected: - principal: admin resource: admin actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_ALLOW delete: EFFECT_ALLOW - principal: admin resource: user1 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_ALLOW delete: EFFECT_ALLOW - principal: admin resource: user2 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_ALLOW delete: EFFECT_ALLOW - principal: user1 resource: admin actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_DENY delete: EFFECT_DENY - principal: user1 resource: user1 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_ALLOW delete: EFFECT_ALLOW - principal: user1 resource: user2 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_DENY delete: EFFECT_DENY - principal: user2 resource: admin actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_DENY delete: EFFECT_DENY - principal: user2 resource: user1 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_DENY delete: EFFECT_DENY - principal: user2 resource: user2 actions: create: EFFECT_ALLOW read: EFFECT_ALLOW update: EFFECT_ALLOW delete: EFFECT_ALLOW