ZRB Toolkit · User Guide

Modelling and Implementing Organizational Information Systems with ZRB

A complete developer's guide to designing, building, and deploying enterprise systems using the Zoned Role-Based framework and its Python toolkit.

Welcome! You are about to embark on a journey to build enterprise systems that are secure by design, maintainable, and perfectly aligned with your organisation's structure. The Zoned Role-Based (ZRB) framework provides a mathematically formal yet practical approach to access control and system architecture. Instead of bolting on security as an afterthought, ZRB makes it an emergent property of how you model your organisation.

This guide is your companion for designing and implementing real-world systems using the ZRB Python toolkit. Whether you are a software architect, a developer, or a security engineer, you will learn how to:

  • Model your enterprise as a hierarchy of zones.
  • Define roles, permissions, and inheritance rules.
  • Enforce fine-grained constraints (separation of duty, temporal, attribute-based).
  • Integrate seamlessly with Django or Flask.
  • Test, simulate, and deploy with confidence.

Throughout the guide we use concrete examples — a university, a hospital, an e-commerce platform, a project management tool, and a banking system — to illustrate every concept. By the end, you will be equipped to apply ZRB to your own projects and build systems that are not only robust but also a joy to maintain.

Part 01

Introduction to ZRB

The framework, the methodology, and what the toolkit provides.

The Zoned Role-Based (ZRB) framework is a comprehensive methodology for building secure, maintainable enterprise systems. It extends traditional RBAC by introducing zones — hierarchical organizational units that mirror the real-world structure of an enterprise. Within each zone, roles are defined, and permissions are assigned to operations. Zones can contain sub-zones, forming a zone tree. Roles can inherit permissions from other roles within the same zone (intra-zone hierarchy) and from roles in parent zones (inter-zone inheritance via gamma mappings). Additionally, constraints (separation of duty, temporal, attribute, context) provide fine-grained control over access.

The ZRB Python toolkit implements this methodology, providing:

  • A core model for zones, roles, operations, users, and constraints.
  • A storage abstraction (with a SQLAlchemy backend) for persistence.
  • An access control engine that computes effective permissions and evaluates constraints efficiently, with caching.
  • Web framework integrations (Django, Flask) with decorators to protect views.
  • A command-line interface for configuration management.
  • Validation utilities to detect conflicts.

This guide walks you through designing an enterprise system with ZRB and implementing it using the toolkit.

Part 02

Core Concepts

The building blocks of every ZRB model.

Zones #

A zone represents an organizational unit. Zones form a tree; the root is the entire enterprise. Each zone has id, name, and parent_id.

Roles #

A role is a job function within a specific zone. Roles have id, zone_id, name, optional parent_role_id, and base_permissions.

Operations #

An operation is a minimal executable action (e.g., grade:submit, order:create). Operations are identified by a unique string and belong to an application.

Users #

Users are individuals who can be assigned to roles within zones. Each user has id, username, email, and optional attributes.

Gamma Mappings #

Inter-zone inheritance: a role in a child zone inherits from a role in a parent zone. A gamma mapping specifies child_zone_id, child_role_id, parent_zone_id, parent_role_id, optional weight, and priority.

Constraints #

  • Separation of Duty (SoD): prohibits a user from performing an action if they hold another role or are the resource owner.
  • Temporal: allows access only during specific time windows.
  • Attribute: checks user or resource attributes against thresholds.
  • Context: requires certain key-value pairs in the request context.

Access Modes #

  • Direct (n_rzbac): only base permissions of the assigned roles are considered.
  • Inferential (i_rzbac): full effective permissions, including intra-zone and inter-zone inheritance.
Part 03

Designing a System with ZRB

Six steps from organisational analysis to user assignment.

Step 1: Model the Organizational Structure

Identify all organizational units (departments, teams, projects). Draw a tree.

Step 2: Define Operations

List every action that requires protection. Group them by application.

Step 3: Define Roles per Zone

For each zone, list the job functions. Decide which operations each role should have directly. Then define intra-zone hierarchies using parent_role_id.

Step 4: Plan Inter-Zone Inheritance

Decide which roles in child zones should inherit from roles in parent zones. Create gamma mappings for each such relationship.

Step 5: Identify Constraints

Add separation of duty, temporal, or attribute-based rules.

Step 6: Assign Users to Roles

Map actual users to roles in specific zones.

The output of the design phase is a ZRB configuration — a YAML/JSON file containing all entities. This configuration is then loaded into the toolkit's storage.
Part 04

Getting Started with the ZRB Toolkit

Install, initialise, and import.

Installation

pip install zrb-toolkit

This installs the core library, SQLAlchemy storage, and the CLI.

Basic Components

  • Storage: SQLAlchemyStore — connects to a database (SQLite, PostgreSQL, etc.).
  • Engine: AccessEngine — the main decision-maker.
  • Web Integrations: zrb.web.django and zrb.web.flask provide middleware and decorators.

Initialising the Database

from zrb.storage.sqlalchemy import SQLAlchemyStore
store = SQLAlchemyStore('sqlite:///zrb.db')
store.create_all()  # creates tables
Part 05

Defining the ZRB Configuration

Load configuration from YAML.

zones:
  - id: root
    name: University
  - id: eng
    name: Faculty of Engineering
    parent_id: root
  - id: cs
    name: Computer Science
    parent_id: eng

operations:
  - id: grade:view
    app_name: grading
    name: View grades
  - id: grade:submit
    app_name: grading
    name: Submit grades

roles:
  - id: prof_eng
    zone_id: eng
    name: Professor
    base_permissions: ["grade:submit", "course:view"]
  - id: prof_cs
    zone_id: cs
    name: Professor
    base_permissions: []   # inherits via gamma

gamma_mappings:
  - child_zone_id: cs
    child_role_id: prof_cs
    parent_zone_id: eng
    parent_role_id: prof_eng
    priority: 1

constraints:
  - id: temporal_grade_submit
    type: temporal
    target: { operation_id: "grade:submit" }
    condition: { time_range: ["2025-05-01T00:00", "2025-06-15T23:59"] }
    is_negative: false
    priority: 10

users:
  - id: u1
    username: alice
    email: alice@uni.edu
    attributes: {}

assignments:
  - user_id: u1
    zone_id: cs
    role_id: prof_cs

Loading the Configuration

zrb import --db sqlite:///zrb.db config.yaml

Or in Python:

import yaml
from zrb.storage.sqlalchemy import SQLAlchemyStore
store = SQLAlchemyStore('sqlite:///zrb.db')
with open('config.yaml') as f:
    config = yaml.safe_load(f)
# ... loop and create objects (as shown in management commands)
Part 06

Integrating with Web Frameworks

Django and Flask are supported out of the box.

6.1 Django Integration #

Middleware

Add 'zrb.web.django.ZRBDjango' to MIDDLEWARE. You need to configure it to resolve the current zone:

# middleware.py
from django.conf import settings
from zrb.storage.sqlalchemy import SQLAlchemyStore
from zrb.web.django import ZRBDjango

zrb_store = SQLAlchemyStore(settings.ZRB_DATABASE_URL)

class ZoneMiddleware(ZRBDjango):
    def __init__(self, get_response):
        super().__init__(get_response)
        self.store = zrb_store

    def _zone_from_request(self, request):
        host = request.get_host().split(':')[0]
        subdomain = host.split('.')[0] if '.' in host else None
        mapping = {
            'cs': 'cs',
            'eng': 'eng',
            None: 'root',
        }
        zone_id = mapping.get(subdomain, 'root')
        return self.store.get_zone(zone_id)

Decorators

from zrb.web.django import i_rzbac, n_rzbac

@login_required
@i_rzbac(operation='grade:view')
def view_grades(request):
    # ...
    pass

The decorator automatically retrieves the current user, the current zone, the operation, calls engine.decide(), and returns HttpResponseForbidden if denied.

6.2 Flask Integration #

from flask import Flask
from zrb.web.flask import ZRBFlask
from zrb.storage.sqlalchemy import SQLAlchemyStore
from zrb.engine.access import AccessEngine

app = Flask(__name__)
store = SQLAlchemyStore('sqlite:///zrb.db')
engine = AccessEngine(store)
zrb = ZRBFlask(app, engine)
@app.route('/grades')
@login_required
@zrb.i_rzbac(operation='grade:view')
def view_grades():
    return jsonify(grades=...)
Part 07

Implementing Constraints

Constraints rely on the context dictionary passed to the decision function.

Built-in Constraint Evaluators

  • SoD: context key (e.g., creator_id) compared with user.id.
  • Temporal: current_time (ISO) checked against time_range.
  • Attribute: user or context attribute compared using operator.
  • Context: context keys matched against expected values.

Providing Context in Django Views

def my_view(request):
    context = {'amount': request.POST.get('amount')}
    user = store.get_user(str(request.user.id))
    op = store.get_operation('withdraw')
    zone = request.zone
    if not engine.decide(user, op, zone, mode='inferential', context=context):
        return HttpResponseForbidden()
Part 08

Testing and Simulation

Use the engine's decide() method for unit testing.

def test_professor_can_submit_grades():
    store = SQLAlchemyStore('sqlite:///test.db')
    # ... load test config ...
    engine = AccessEngine(store)
    user = store.get_user('u1')
    zone = store.get_zone('cs')
    op = store.get_operation('grade:submit')
    assert engine.decide(user, op, zone) is True
Part 09

Advanced Topics

Custom constraints, custom storage, and performance tuning.

9.1 Custom Constraint Evaluators #

from zrb.constraints.base import ConstraintEvaluator
from zrb.constraints.registry import ConstraintRegistry

class WeekendEvaluator(ConstraintEvaluator):
    def evaluate(self, constraint, user, role, zone, operation, context=None):
        from datetime import datetime
        weekday = datetime.now().strftime('%a')
        return weekday in constraint.condition.get('days', [])

registry = ConstraintRegistry()
registry._evaluators['weekend'] = WeekendEvaluator()

9.2 Custom Storage Backend #

Implement the Storage interface (see zrb.storage.base.Storage) and pass it to the engine.

9.3 Performance Tuning #

  • The engine caches effective permissions with a TTL.
  • For high-traffic systems, use Redis or Memcached as a cache backend.
  • Ensure database indexes on foreign keys.
Part 10

Best Practices

Advice from real deployments.

  1. Start with a clear zone tree: involve business stakeholders.
  2. Keep role hierarchies shallow: deep hierarchies are hard to debug.
  3. Use gamma mappings sparingly: prefer intra-zone inheritance.
  4. Name operations consistently: use app:action.
  5. Version your ZRB configuration: store it in version control.
  6. Test constraints thoroughly: unit tests for each scenario.
  7. Monitor performance: log cache hit rates and decision latency.
  8. Document roles and permissions: maintain a human-readable matrix.
Part 11

Conclusion

Security as an emergent property of good design.

The ZRB methodology and toolkit provide a powerful, formal approach to building secure enterprise systems. By aligning access control with organizational structure, you reduce complexity, improve maintainability, and ensure that security is an emergent property of the design, not an afterthought.

Now go build systems that are secure by design! Start with the hands-on tutorial if you prefer a guided path, or clone the ZRB Toolkit repository and explore the example projects.
👤