Loading content...
Traditional authorization models answer: "Can user X access resource Y?" But modern systems require richer questions:
These questions involve context—attributes of the subject, resource, action, and environment that go beyond static role assignments or fixed security labels.
Attribute-Based Access Control (ABAC) addresses this by making authorization decisions based on attributes evaluated at access time. Instead of "Alice has role Admin," we express "Allow if subject.department == resource.department AND action.type == 'read' AND environment.time_of_day between 09:00 and 17:00."
ABAC is the most flexible authorization model, capable of expressing policies that would require vast numbers of roles in RBAC or complex label hierarchies in MAC. This flexibility comes with complexity—policy design, evaluation performance, and auditing become more challenging.
ABAC is increasingly important in cloud computing, microservice architectures, and zero-trust security models where context-aware decisions are essential.
This page covers ABAC concepts and architecture, attribute categories, policy languages (XACML, Rego, Cedar), policy evaluation, ABAC in cloud platforms (AWS IAM, Azure, GCP), performance and scalability considerations, and how ABAC relates to other authorization models.
The ABAC Model
ABAC authorization decisions are based on four categories of attributes:
Subject Attributes — Properties of the entity requesting access
Resource Attributes — Properties of the resource being accessed
Action Attributes — Properties of the requested operation
Environment Attributes — Contextual conditions at access time
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
// ABAC Conceptual Model // Attribute Categoriesinterface SubjectAttributes { id: string; email: string; department: string; clearance: SecurityLevel; roles: Set<string>; location: {country: string, office: string}; device: {type: string, managed: boolean}; authMethod: "password" | "mfa" | "certificate";} interface ResourceAttributes { id: string; type: "document" | "database" | "api" | "file"; classification: "public" | "internal" | "confidential" | "restricted"; owner: string; department: string; createdAt: Timestamp; region: string;} interface ActionAttributes { type: "read" | "write" | "delete" | "admin"; method: string; // e.g., "GET", "POST", "DELETE" scope: Set<string>; // Requested permissions} interface EnvironmentAttributes { currentTime: Timestamp; dayOfWeek: string; clientIP: string; networkZone: "internal" | "vpn" | "external"; threatLevel: "low" | "medium" | "high" | "critical"; requestId: string;} // Authorization Requestinterface AuthorizationRequest { subject: SubjectAttributes; resource: ResourceAttributes; action: ActionAttributes; environment: EnvironmentAttributes;} // Authorization Decisiontype Decision = "permit" | "deny" | "not_applicable" | "indeterminate"; // Policy Engine evaluates request against policiesfunction evaluate(request: AuthorizationRequest, policies: Policy[]): Decision;ABAC Architecture
A standard ABAC implementation has these components:
Policy Enforcement Point (PEP) — The component that intercepts access requests and enforces decisions. This could be an API gateway, service mesh sidecar, or application middleware.
Policy Decision Point (PDP) — The engine that evaluates policies against attributes and returns access decisions. This is typically a dedicated authorization service.
Policy Information Point (PIP) — Sources of attribute data. PIPs fetch subject attributes from identity providers, resource attributes from resource metadata services, etc.
Policy Administration Point (PAP) — The interface for creating, updating, and managing policies.
Policy Repository — Storage for policies, typically a database or configuration store.
| Component | Role | Example Implementation |
|---|---|---|
| PEP | Intercept requests, enforce decisions | API Gateway, sidecar proxy, middleware |
| PDP | Evaluate policies, return decisions | OPA, AWS Policy Engine, Cedar |
| PIP | Provide attribute values | LDAP, HR database, identity provider |
| PAP | Policy management interface | Console, API, Git-based workflows |
| Repository | Store policies | Database, object storage, Git |
ABAC encourages 'externalized authorization'—moving policy decisions out of application code into a centralized service. Instead of if (user.isAdmin) scattered through code, applications call a policy service. This enables consistent policy enforcement, central auditing, and policy changes without application deployment.
eXtensible Access Control Markup Language (XACML) is the OASIS standard for ABAC policy specification. While verbose (XML-based), it provides a comprehensive framework that influenced all subsequent ABAC systems.
XACML Structure
Policies are organized hierarchically:
Each policy specifies:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
<?xml version="1.0" encoding="UTF-8"?><Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="document-access-policy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"> <Description>Policy for document access control</Description> <!-- Target: This policy applies to document resources --> <Target> <AnyOf> <AllOf> <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">document</AttributeValue> <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="resource-type" DataType="http://www.w3.org/2001/XMLSchema#string"/> </Match> </AllOf> </AnyOf> </Target> <!-- Rule 1: Allow read if same department --> <Rule RuleId="same-department-read" Effect="Permit"> <Description>Users can read documents from their department</Description> <Condition> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and"> <!-- Action must be read --> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">read</AttributeValue> <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" AttributeId="action-id" DataType="http://www.w3.org/2001/XMLSchema#string"/> </Apply> <!-- Subject department must match resource department --> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"> <AttributeDesignator Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" AttributeId="department" DataType="http://www.w3.org/2001/XMLSchema#string"/> <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="department" DataType="http://www.w3.org/2001/XMLSchema#string"/> </Apply> </Apply> </Condition> </Rule> <!-- Rule 2: Allow during business hours from internal network --> <Rule RuleId="business-hours-internal" Effect="Permit"> <Condition> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and"> <!-- Time between 9:00 and 17:00 --> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-greater-than-or-equal"> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only"> <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" AttributeId="current-time" DataType="http://www.w3.org/2001/XMLSchema#time"/> </Apply> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">09:00:00</AttributeValue> </Apply> <!-- Network is internal --> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">internal</AttributeValue> <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" AttributeId="network-zone" DataType="http://www.w3.org/2001/XMLSchema#string"/> </Apply> </Apply> </Condition> </Rule> <!-- Default: Deny if no rules match --> <Rule RuleId="default-deny" Effect="Deny"/></Policy>Combining Algorithms
When multiple rules or policies could apply, combining algorithms determine the final decision:
| Algorithm | Behavior |
|---|---|
| Deny-overrides | If any rule denies, final decision is deny |
| Permit-overrides | If any rule permits, final decision is permit |
| First-applicable | First matching rule determines decision |
| Only-one-applicable | Exactly one policy must match, otherwise indeterminate |
| Ordered-deny/permit-overrides | Like deny/permit-overrides but considers order |
XACML Request/Response
Requests are also XML documents containing attribute values. The PDP evaluates the request against policies and returns a decision (Permit, Deny, NotApplicable, Indeterminate) along with optional obligations (actions the PEP must perform).
XACML's verbosity has limited adoption despite its comprehensiveness. Many organizations prefer lighter-weight alternatives (Rego, Cedar) while using XACML concepts. However, XACML remains influential in enterprise and government systems requiring formal standardization.
Modern policy languages learned from XACML but prioritize readability and developer experience. Let's examine three influential languages.
Open Policy Agent (OPA) and Rego
OPA is a general-purpose policy engine, and Rego is its declarative policy language. Rego (pronounced "ray-go") uses logic programming inspired by Datalog.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
# OPA/Rego Policy Example package application.authz # Default denydefault allow = false # Allow if user is adminallow { input.subject.roles[_] == "admin"} # Allow read access to documents in same departmentallow { input.action == "read" input.resource.type == "document" input.subject.department == input.resource.department} # Allow during business hours from internal networkallow { input.action == "read" is_business_hours is_internal_network} is_business_hours { hour := time.clock(time.now_ns())[0] hour >= 9 hour < 17 weekday := time.weekday(time.now_ns()) weekday != "Saturday" weekday != "Sunday"} is_internal_network { net.cidr_contains("10.0.0.0/8", input.environment.client_ip)} # Complex rule: approval workflowallow { input.action == "approve" input.resource.type == "expense" # User must not be the submitter input.subject.id != input.resource.submitter_id # User's approval limit must cover the amount input.subject.approval_limit >= input.resource.amount # User must be in approvers chain input.subject.id == input.resource.approvers[_]} # Obligations: actions PEP must takeobligations["log_access"] { input.resource.classification == "confidential"} obligations["require_mfa"] { input.resource.classification == "restricted" input.subject.auth_method != "mfa"}AWS Cedar
Cedar is Amazon's purpose-built authorization policy language, used in Amazon Verified Permissions and AWS services. It emphasizes formal verification and performance.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
// Cedar Policy Examples // Allow users to view their own profilepermit ( principal, action == Action::"viewProfile", resource) when { principal == resource.owner}; // Allow managers to view reports of their direct reportspermit ( principal, action == Action::"viewReport", resource) when { resource.owner in principal.directReports}; // Allow document access based on department and classificationpermit ( principal, action in [Action::"read", Action::"list"], resource is Document) when { principal.department == resource.department && principal.clearance >= resource.classification}; // Time-based access restrictionpermit ( principal is Employee, action == Action::"accessProdData", resource) when { context.currentHour >= 9 && context.currentHour < 18 && context.dayOfWeek in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]}; // Forbid: explicit deny for terminated employeesforbid ( principal is Employee, action, resource) when { principal.status == "terminated"}; // Group-based access with hierarchypermit ( principal in Group::"DataAnalysts", action == Action::"query", resource is Dataset) when { resource.accessLevel == "analytics"};| Aspect | XACML | Rego (OPA) | Cedar |
|---|---|---|---|
| Syntax | XML | Datalog-like | Purpose-built DSL |
| Verbosity | Very high | Medium | Low |
| Learning Curve | Steep | Moderate | Gentle |
| Formal Verification | Limited | Testing-focused | Built-in analyzer |
| Performance | Moderate | Good (with compilation) | Excellent (optimized) |
| Ecosystem | Enterprise tools | Kubernetes, APIs, Envoy | AWS services |
| Standards Body | OASIS | CNCF | Amazon (open source) |
Cloud platforms heavily leverage ABAC for fine-grained access control. Let's examine major implementations.
AWS IAM Policy Language
AWS IAM uses a JSON-based policy language with ABAC elements:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowReadOwnDepartmentResources", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": "arn:aws:s3:::company-data/*", "Condition": { "StringEquals": { "s3:ExistingObjectTag/Department": "${aws: PrincipalTag/ Department }" } } }, { "Sid": "AllowEC2ActionsInSameProject", "Effect": "Allow", "Action": [ "ec2:StartInstances", "ec2:StopInstances" ], "Resource": "*", "Condition": { "StringEquals": { "ec2:ResourceTag/Project": "${aws:PrincipalTag/Project}" } } }, { "Sid": "DenyOutsideBusinessHours", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "DateGreaterThan": { "aws:CurrentTime": "2024-01-01T17:00:00Z" }, "DateLessThan": { "aws:CurrentTime": "2024-01-02T09:00:00Z" } } }, { "Sid": "RequireMFAForSensitiveActions", "Effect": "Deny", "Action": [ "iam:*", "organizations:*" ], "Resource": "*", "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } } }, { "Sid": "AllowFromVPCOnly", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "StringNotEquals": { "aws:SourceVpc": "vpc-12345678" } } } ]} ** AWS IAM Condition Keys **
AWS provides numerous condition keys for ABAC:
| Category | Example Keys | Purpose |
|---|---|---|
| Principal | aws: PrincipalTag/*, aws:userid | Subject attributes |
| Resource | s3:ExistingObjectTag/, ec2:ResourceTag/ | Resource attributes |
| Request | aws:RequestTag/*, s3:prefix | Action attributes |
| Environment | aws:CurrentTime, aws:SourceIp, aws:SourceVpc | Context |
| Authentication | aws:MultiFactorAuthPresent, aws:TokenIssueTime | Auth context |
Azure ABAC
Azure's Attribute-Based Access Control builds on Azure RBAC with conditions:
12345678910111213141516171819
// Azure ABAC Role Assignment with Conditions { "roleDefinitionId": "/subscriptions/.../providers/Microsoft.Authorization/roleDefinitions/...", "principalId": "user-guid", "condition": "((!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'})) OR (@Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags:Project] StringEquals @Principal[tags.Project]))", "conditionVersion": "2.0"} // Translated condition:// If action is blob read, then:// resource's Project tag must equal principal's Project tag// Otherwise (different action): allow based on role only // Azure Condition Operators:// - StringEquals, StringNotEquals// - StringLike, StringNotLike (wildcard matching)// - DateTimeGreaterThan, DateTimeLessThan// - @Resource[...], @Principal[...], @Request[...]The most common cloud ABAC pattern is tag matching: resources and principals both have tags (key-value pairs), and policies grant access when tags match. This enables 'users with Project=Alpha can access resources with Project=Alpha' without listing specific resource ARNs. It scales well but requires disciplined tagging.
ABAC's flexibility comes at a cost: policy evaluation can become a performance bottleneck. Understanding evaluation mechanics is crucial for scalable implementations.
Evaluation Flow
Performance Considerations
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
// ABAC Performance Optimization Strategies // 1. Policy Indexing - Don't evaluate all policies for every requestclass PolicyIndex { // Index policies by their target criteria private byResourceType: Map<ResourceType, Set<Policy>>; private byAction: Map<Action, Set<Policy>>; function getApplicablePolicies(request: AuthzRequest): Set<Policy> { // Quick filter: only policies that could apply let byResource = this.byResourceType.get(request.resource.type) ?? Set(); let byAction = this.byAction.get(request.action) ?? Set(); // Intersection: policies that match both return byResource.intersection(byAction); }} // 2. Partial Evaluation / Pre-computation// For policies that don't change often, pre-compute partial results function precomputeStaticConditions(policy: Policy, subject: Subject): PartialPolicy { // Evaluate conditions that only depend on subject (don't change per-request) // subject.department == "Engineering" -> true/false (fixed for session) // subject.clearance >= resource.classification -> UNKNOWN (depends on resource) return policy.withPartialEvaluation(subject);} // 3. Caching authorization decisionsclass AuthzCache { // Cache key must include all attributes that affect decision function cacheKey(request: AuthzRequest): string { return hash( request.subject.id, request.action, request.resource.id, // Include relevant environmental factors request.environment.networkZone, // Don't include: precise timestamp (would never hit cache) // Do include: time bucket (hour or business/non-business) Math.floor(request.environment.currentTime / HOUR) ); } // Short TTL for security-sensitive decisions cacheTTL = 60.seconds;} // 4. Push-based vs Pull-based attribute retrieval// Pull-based: PDP queries PIP for each attribute on each request (slow)// Push-based: Attributes are pushed to PDP and cached (faster, eventual consistency) // 5. Policy compilation// OPA compiles Rego to WebAssembly for fast evaluation// Cedar uses partial evaluation and optimized constraint solving| Metric | Target | Impact Area |
|---|---|---|
| Evaluation latency (P99) | < 5ms | User experience, API SLAs |
| Throughput | 10,000 decisions/sec | High-traffic services |
| Policy load time | < 1s | Deployment speed |
| Attribute fetch time | < 2ms | Overall latency budget |
| Cache hit rate | 80% | Reduced PDP load |
Scaling ABAC
For high-scale systems:
Caching authorization decisions introduces risk: if a user's access is revoked, cached permits may allow continued access until cache expires. Balance cache TTL against security requirements. For sensitive operations, consider no caching or very short TTLs. For read-heavy, less sensitive operations, longer TTLs are acceptable.
Designing effective ABAC policies requires balancing expressiveness with manageability. Poor policy design leads to security gaps, administrative nightmares, or unintended access.
Policy Design Principles
1. Start with Deny by Default Every request should be denied unless explicitly permitted. This ensures new resources/actions are protected until policies are created.
2. Prefer Positive Policies (Permit) Over Negative (Deny) Deny rules should be exceptions, not the norm. "Permit if X, Y, Z" is clearer than "Deny unless not-X, not-Y, not-Z."
3. Keep Policies Focused Each policy should address one concern. Don't create "god policies" that handle everything—they become impossible to maintain.
4. Document Policy Intent Policy syntax shows what it does; comments explain why. Future maintainers need to understand intent to modify safely.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
# ABAC Policy Design Patterns package patterns # Pattern 1: Role-based with ABAC extension# Use roles for coarse access, attributes for fine-grained # Base role permissionbase_allow { "analyst" in input.subject.roles input.action == "read" input.resource.type == "report"} # ABAC refinement: same region onlyallow { base_allow input.subject.region == input.resource.region} # Pattern 2: Hierarchical ownership# Allow access to resources owned by user or their organizational ancestors allow { input.action == "read" owner := input.resource.owner is_org_ancestor(input.subject.org_path, owner)} is_org_ancestor(user_path, owner) { # user_path: ["company", "engineering", "frontend"] # owner: "engineering" -> true (ancestor) user_path[_] == owner} # Pattern 3: Break-glass / emergency access# Allow privileged access with extra logging allow { input.context.break_glass == true input.subject.id in data.break_glass_authorized_users} # Obligation: log break-glass accessmust_log["break_glass_audit"] { input.context.break_glass == true} # Pattern 4: Time-windowed access# Temporary permissions with expiration allow { grant := data.temporary_grants[_] grant.subject == input.subject.id grant.action == input.action grant.resource == input.resource.id time.now_ns() >= grant.valid_from time.now_ns() < grant.valid_until} # Pattern 5: Approval workflows# Access requires prior approval record allow { input.action == "delete" input.resource.type == "production_data" # Must have approval record approval := data.approvals[_] approval.request_id == input.context.request_id approval.approved == true approval.approver != input.subject.id # Cannot self-approve # Approval must be recent time.now_ns() - approval.timestamp < 24 * 60 * 60 * 1000000000 # 24 hours in ns}Common Policy Anti-Patterns
| Anti-Pattern | Problem | Better Approach |
|---|---|---|
| Hardcoded IDs | Policy breaks when IDs change | Use attributes, groups, or roles |
| Overly complex conditions | Hard to maintain, easy to get wrong | Break into smaller policies |
| Permit-all with deny exceptions | Easy to miss edge cases | Default deny with permit rules |
| Duplicated logic | Inconsistent updates | Extract to reusable rules |
| No policy namespacing | Conflicts when combining | Use packages/namespaces |
Treat policies as code: write unit tests for policy rules, integration tests for policy sets, and regression tests when modifying policies. OPA supports test_ prefixed rules for assertions. Cedar has formal analysis to catch inconsistencies. Test that intended access is granted AND that unintended access is denied.
ABAC's expressiveness makes security analysis more challenging than simpler models. Ensuring policies achieve their security goals requires systematic analysis.
Policy Analysis Questions
Formal Analysis with Cedar
Cedar includes an analyzer for policy verification:
12345678910111213141516171819202122232425262728293031323334353637383940414243
// Cedar Policy Analysis Examples // Policy set to analyzepermit ( principal in Group::"Engineers", action == Action::"read", resource is CodeRepository); permit ( principal in Group::"SeniorEngineers", action in [Action::"read", Action::"write"], resource is CodeRepository); forbid ( principal, action, resource) when { resource.restricted == true && !(principal in Group::"Security")}; // Analysis queries (Cedar Analyzer) // Query 1: Can any non-Security user access restricted resources?// Expected: No (forbid rule should block)// analyzer.canAccess(// principal not in Group::"Security",// action,// resource where resource.restricted == true// ) => false // Query 2: What can Engineers do that SeniorEngineers cannot?// Expected: Nothing (SeniorEngineers is superset)// analyzer.compare(Group::"Engineers", Group::"SeniorEngineers") // Query 3: Is there any permit that the forbid doesn't block?// Finds policy conflicts/gaps // Query 4: Policy change impact// "If we add 'production: true' to resource, who loses access?"Testing Strategies
1. Property-Based Testing Assert properties that should always hold:
2. Negative Testing Explicitly test that unauthorized access is denied:
3. Boundary Testing Test at policy boundaries:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
# OPA Rego Policy Tests package application.authz # Test: Admins can access everythingtest_admin_allow { allow with input as { "subject": {"roles": ["admin"]}, "action": "delete", "resource": {"type": "any"} }} # Test: Non-admin cannot deletetest_non_admin_cannot_delete { not allow with input as { "subject": {"roles": ["user"]}, "action": "delete", "resource": {"type": "document"} }} # Test: Same department can readtest_same_department_read { allow with input as { "subject": {"department": "engineering"}, "action": "read", "resource": {"type": "document", "department": "engineering"} }} # Test: Different department cannot readtest_different_department_cannot_read { not allow with input as { "subject": {"department": "sales"}, "action": "read", "resource": {"type": "document", "department": "engineering"} }} # Test: Business hours from internal networktest_business_hours_internal { allow with input as { "subject": {"department": "any"}, "action": "read", "resource": {"type": "document", "department": "any"} } with time.now_ns as 1609502400000000000 # 10:00 AM with data.internal_cidrs as ["10.0.0.0/8"] with input.environment.client_ip as "10.1.2.3"} # Test: Outside business hours deniedtest_outside_hours_denied { not allow with input as { "subject": {"roles": ["user"]}, "action": "read", "resource": {"type": "document"} } with time.now_ns as 1609545600000000000 # 10:00 PM}Integrate policy tests into CI/CD pipelines. Every policy change should pass tests before deployment. Consider canary deployments for policies—route a percentage of authorization requests to new policies while monitoring for unexpected denials.
Having studied all major authorization models, let's compare them systematically to guide model selection.
Expressiveness Hierarchy
ABAC ⊃ RBAC ⊃ DAC (in terms of what can be expressed)
Model Selection Guide
| Requirement | DAC | MAC | RBAC | ABAC |
|---|---|---|---|---|
| Simple file sharing | ✅ Best | ❌ | ➖ | ➖ Overkill |
| Multi-tenant SaaS | ❌ | ➖ | ✅ Good | ✅ Best |
| Government/military | ❌ | ✅ Required | ➖ | ✅ With MLS |
| Enterprise IT | ❌ | ➖ | ✅ Best | ✅ Growing |
| Microservices | ❌ | ❌ | ➖ | ✅ Best |
| Zero-trust architecture | ❌ | ❌ | ➖ | ✅ Required |
| API authorization | ❌ | ❌ | ✅ Good | ✅ Best |
| Simple embedded system | ✅ Best | ➖ | ❌ | ❌ |
Hybrid Approaches
Real systems often combine models:
RBAC + ABAC Use RBAC for coarse-grained access based on organizational role, add ABAC for fine-grained context-dependent conditions.
Example: "Analysts can read reports" (RBAC) + "only reports from their region during business hours" (ABAC)
MAC + DAC System-wide classification labels (MAC) overlay user-controlled sharing (DAC). Common in government systems where classified data has mandatory labels but users can share within classification.
RBAC + MAC Roles determine what you can potentially access, labels determine what you're actually allowed to access. Windows combines RBAC-style group membership with Mandatory Integrity Control.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
# Hybrid RBAC + ABAC Policy Example package hybrid.authz import future.keywords.in # Default denydefault allow = false # Layer 1: RBAC - Role-based coarse accessrole_permits_action { # Define role-action mappings role_permissions := { "admin": {"read", "write", "delete", "admin"}, "editor": {"read", "write"}, "viewer": {"read"}, "analyst": {"read", "export"}, } # Check if any of user's roles permit the action some role in input.subject.roles input.action in role_permissions[role]} # Layer 2: ABAC - Attribute-based refinementabac_permits_access { # Same organization input.subject.org_id == input.resource.org_id # Classification check (MAC-like) clearance_levels := {"public": 0, "internal": 1, "confidential": 2, "secret": 3} clearance_levels[input.subject.clearance] >= clearance_levels[input.resource.classification]} # Layer 3: Context - Environmental conditionscontext_permits_access { # Internal network OR VPN with MFA internal_or_vpn_mfa # Not during maintenance window not in_maintenance_window} internal_or_vpn_mfa { input.environment.network == "internal"} internal_or_vpn_mfa { input.environment.network == "vpn" input.subject.mfa_verified == true} in_maintenance_window { # Saturday 2-6 AM time.weekday(time.now_ns()) == "Saturday" hour := time.clock(time.now_ns())[0] hour >= 2 hour < 6} # Final decision: ALL layers must permitallow { role_permits_action # RBAC layer abac_permits_access # ABAC layer context_permits_access # Environmental layer}Organizations typically evolve: DAC → RBAC → RBAC+ABAC. Start simple, add complexity as requirements demand. Don't implement full ABAC if RBAC suffices—the administrative and performance overhead isn't justified. ABAC's power is for genuinely context-dependent requirements.
Attribute-Based Access Control provides the most flexible authorization model, capable of expressing complex, context-aware policies. Let's consolidate the key concepts.
The Authorization Module Complete
This module has covered the spectrum of authorization models:
Together, these models provide the vocabulary and tools to design authorization systems for any security requirement—from simple file sharing to complex, distributed, zero-trust architectures.
You now have comprehensive knowledge of authorization in operating systems and modern computing—from fundamental theory through practical implementation. You can analyze security requirements, select appropriate models, design policies, and implement authorization systems that scale from embedded devices to global cloud platforms.