Skip to main content

First Look at Cerbos: A Solution for Dynamic Role & Permission Management

Introduce

My next post is about tools for managing roles and dynamically controlling access to resources. Some business requirements demand extreme flexibility, often requiring a combination of RBAC + ABAC at the same time.

From my experience, I’ve seen a lot of solutions, but most don’t cover all the key points. There are three circles that are really hard to combine: Performance, Security, and Flexibility. And when someone tries to implement all three—oh, it’s painful.


But I found a technology that (almost) solves this challenge: Cerbos—a scalable, open-source authorization layer for handling roles and permissions. (Cerbos site)

Why is it good?

Centralized configuration – Everything is managed in one place.
Easy integration – SDKs are available for all popular languages:
    ðŸ”¹ .NET, Go, Java, JS, PHP, Python, Ruby, Rust
Great documentation – Clear examples and guidance.
Playground for testing – No need to run an app or set up tools. Just test and debug your policy inside the Cerbos Playground. Super useful!
YAML-based policies – Simple, readable, and easy for non-developers to configure.

Less talk, more code—let’s go! 🚀

How to start the Cerbos server locally (In my case, running the binary via Brew was faster and easier than using Docker—surprisingly! 👀)

Installation

Link on a repository with code: https://github.com/kolomiietsmykola/cerbos-demo

Description of actions in code 

  • Define a user (principal)
    • "seller" is assigned a "user" role
    • Attribute "regular": true
  • Define resources (product:object)
    • r1 ("Private_Product")owner: seller, public: false
    • r2 ("Product_Card_2")owner: another_seller, public: true
  • Batch check authorization for two actions for a defined a user ("seller") (view:public, edit, and create)

  • Run application without any policies
    Result
    Resource: 'Private_Product_Seller' -> Actions: 'create' -> Status: 'EFFECT_DENY'
    Resource: 'Private_Product_Seller' -> Actions: 'view:public' -> Status: 'EFFECT_DENY'
    Resource: 'Private_Product_Seller' -> Actions: 'edit' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'view:public' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'edit' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'create' -> Status: 'EFFECT_DENY'
    What does it mean? - All actions are DENY, so if the policy does not allow it then it is denied. 
    Possible status: EFFECT_DENY and EFFECT_ALLOW

    Different examples and scenarios 

    The basic policy is the role setup
    apiVersion: "api.cerbos.dev/v1"
    derivedRoles:
    name: common_roles
    definitions:
    - name: owner
    parentRoles: ["user"]
    condition:
    match:
    expr: request.resource.attr.owner == request.principal.id

    - name: admin
    parentRoles: ["owner"]
    condition:
    match:
    expr: request.resource.attr.admin == request.principal.id

    1. Full Access for Product Owners

    • If a user owns a product, they can perform any action ('*' wildcard).
    apiVersion: api.cerbos.dev/v1
    resourcePolicy:
    version: "default"
    importDerivedRoles:
    - common_roles
    resource: "product:object"
    rules:
    - actions: ['*']
    effect: EFFECT_ALLOW
    derivedRoles:
    - owner

    Result
    Resource: 'Private_Product_Seller' -> Actions: 'edit' -> Status: 'EFFECT_ALLOW'
    Resource: 'Private_Product_Seller' -> Actions: 'create' -> Status: 'EFFECT_ALLOW'
    Resource: 'Private_Product_Seller' -> Actions: 'view:public' -> Status: 'EFFECT_ALLOW'
    Resource: 'Public_Product' -> Actions: 'create' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'view:public' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'edit' -> Status: 'EFFECT_DENY'

    2. Limited Access to Private Products for Non-Owners

    • Buyers or other users cannot view private products unless explicitly allowed.
    • The private attribute determines whether a product is public or private.
    • Only owners and moderators can access private products.
    apiVersion: api.cerbos.dev/v1
    resourcePolicy:
    version: "default"
    importDerivedRoles:
    - common_roles
    resource: "product:object"
    rules:
    - actions: ['*']
    effect: EFFECT_ALLOW
    derivedRoles:
    - owner

    - actions: ['view:public']
    effect: EFFECT_ALLOW
    roles:
    - user
    condition:
    match:
    expr: request.resource.attr.public == true

    Result
    Resource: 'Private_Product_Seller' -> Actions: 'create' -> Status: 'EFFECT_ALLOW'
    Resource: 'Private_Product_Seller' -> Actions: 'view:public' -> Status: 'EFFECT_ALLOW'
    Resource: 'Private_Product_Seller' -> Actions: 'edit' -> Status: 'EFFECT_ALLOW'
    Resource: 'Public_Product' -> Actions: 'view:public' -> Status: 'EFFECT_ALLOW'
    Resource: 'Public_Product' -> Actions: 'edit' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'create' -> Status: 'EFFECT_DENY'

    3. Prevent Editing of Flagged Products

    • Even owners cannot edit products if they are flagged.
    • Only moderators or admins can edit flagged products.
    apiVersion: api.cerbos.dev/v1
    resourcePolicy:
    version: "default"
    importDerivedRoles:
    - common_roles
    resource: "product:object"
    rules:
    - actions: ['*']
    effect: EFFECT_ALLOW
    derivedRoles:
    - owner

    - actions: ['edit']
    effect: EFFECT_ALLOW
    derivedRoles:
    - admin
    condition:
    match:
    expr: request.resource.attr.flagged == true

    - actions: ['edit']
    effect: EFFECT_DENY
    derivedRoles:
    - owner
    condition:
    match:
    expr: request.resource.attr.flagged == true
    Result
    Resource: 'Private_Product_Seller' -> Actions: 'edit' -> Status: 'EFFECT_DENY'
    Resource: 'Private_Product_Seller' -> Actions: 'create' -> Status: 'EFFECT_ALLOW'
    Resource: 'Private_Product_Seller' -> Actions: 'view:public' -> Status: 'EFFECT_ALLOW'
    Resource: 'Public_Product' -> Actions: 'edit' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'create' -> Status: 'EFFECT_DENY'
    Resource: 'Public_Product' -> Actions: 'view:public' -> Status: 'EFFECT_DENY'

    Comparing 

    Before choosing something, I need to compare similar solutions in the market and a very popular technology is Zanzibar / SpiceDB. So, Cerbos and Zanzibar/SpiceDB both provide authorization solutions, but they approach the problem in different ways and are suited for different use cases. Here's a comparison:
    FeatureCerbosZanzibar / SpiceDB
    TypePolicy-based Access Control (PBAC)Relationship-based Access Control (ReBAC)
    Core ModelPolicies define roles, attributes, and conditions for access decisionsUses a graph-based model where relationships between users and resources define access
    Best forFine-grained authorization with conditional rules (e.g., attribute-based)Large-scale systems requiring hierarchical and dynamic relationships
    Use CasesEnterprise apps, API authorization, microservicesSocial networks, multi-tenant SaaS, document-sharing apps
    ScalabilityLightweight, fast decision engine (embedded or API-based)Distributed, designed for high-scale and low-latency lookups
    Evaluation SpeedFast, as policies are evaluated in-memory or via APIOptimized for caching and distributed queries but may require DB lookups
    ComplexityEasier to set up, simple YAML policiesMore complex setup, requires database or backend storage
    StorageStateless (no storage required)Requires a database (e.g., CockroachDB, PostgreSQL, memory-based)
    DeploymentCan run as a service or embedded in an appRuns as a distributed service, needs persistent storage
    IntegrationAPI-based, SDKs for multiple languagesAPI-based, supports gRPC and REST, libraries available
    Authorization ModelAttribute-based and role-based (ABAC/RBAC)Relationship-based (ReBAC), similar to Google's Zanzibar
    FlexibilitySupports custom conditions and attributesSupports dynamic relationships and hierarchical permissions
    ExamplesControlling API access based on roles, attributes, or user contextManaging access in collaboration tools, social networks, or large-scale multi-tenant applications

    When to Use Cerbos

    • If you need fine-grained access control with attribute-based conditions.
    • If you want a lightweight authorization engine without needing a database.
    • If your application has a simple or moderate complexity access model.
    • If you prefer YAML-based policies for easier management.

    When to Use Zanzibar/SpiceDB

    • If you need Google Zanzibar-like scalability for millions of relationships.
    • If your application requires complex, hierarchical relationships for access control.
    • If you want highly dynamic access control, like in social networks or SaaS platforms.
    • If you can manage a dedicated database for access control storage.
    So, they are resolve different problems and really hard to compare them, but we see that we have one more solution to improve authorization and granting access to resources.  

    Summary

    Cerbos is a powerful open-source authorization layer that helps manage roles and permissions dynamically. Many solutions struggle to balance Performance, Security, and Flexibility, but Cerbos comes close to solving this challenge. It offers centralized configuration, easy integration with multiple languages, a YAML-based policy system for simplicity, and a Playground for quick testing. My first impression? It’s well-documented, developer-friendly, and surprisingly easy to set up



    Comments

    Popular posts from this blog

    Why Microsoft Azure Well-Architected Framework Can Improve Architecture

    Small and medium-sized businesses often face a common challenge: the absence of experienced cloud engineers. Due to limited resources, teams typically choose the quickest path—getting things done in the easiest, fastest way. Unfortunately, this approach often leads to solutions that aren't secure, cost too much, and become nearly impossible to extend or manage effectively. Recognizing this critical challenge, Microsoft Azure has developed the Well-Architected Framework. This comprehensive set of guidelines and best practices helps businesses assess their existing solutions and guides them toward building robust, secure, cost-effective, and manageable cloud infrastructures from the start. The Azure Well-Architected Framework is structured around five essential pillars: Cost Optimization : Ensuring that cloud resources are used efficiently and effectively, reducing unnecessary expenses. Operational Excellence : Focusing on the ability to run and monitor systems effectively, ensuring ...

    "Dushnylo" Series: Monolith First approach.

    I keep hearing, “You MUST start with a monolith.” Every new project? Always? When I hear that, two thoughts immediately come to mind:      1️⃣ “It depends.” You can’t just blindly say every project must start as a monolith.      2️⃣ My inner Dushnylo whispers: “Time to make a post about this.” So, here’s my take: I disagree. Not only do I disagree, but I believe the most critical and dangerous part of system design is analyzing and understanding business needs before making architectural decisions. Why? Simple. Imagine you’re building a streaming platform that processes massive amounts of data, handles notifications, and integrates with third-party services. Does this sound like something you’d build as a pure monolith? Of course not. But I do agree on one thing—you have to start somewhere. That starting point could be a simple core application —yes, it might look like a monolith at first. But you’re not designing the entire system as a monolith. ...