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.
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.
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.
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.
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.djangoandzrb.web.flaskprovide middleware and decorators.
Initialising the Database
from zrb.storage.sqlalchemy import SQLAlchemyStore
store = SQLAlchemyStore('sqlite:///zrb.db')
store.create_all() # creates tables
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)
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=...)
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 withuser.id. - Temporal:
current_time(ISO) checked againsttime_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()
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
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.
Best Practices
Advice from real deployments.
- Start with a clear zone tree: involve business stakeholders.
- Keep role hierarchies shallow: deep hierarchies are hard to debug.
- Use gamma mappings sparingly: prefer intra-zone inheritance.
- Name operations consistently: use
app:action. - Version your ZRB configuration: store it in version control.
- Test constraints thoroughly: unit tests for each scenario.
- Monitor performance: log cache hit rates and decision latency.
- Document roles and permissions: maintain a human-readable matrix.
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.