Back to Blog

ABAC Implementation: Attribute-Based Fine-Grained Access Control

ABAC (Attribute-Based Access Control) is the second layer in coomia-dip's three-layer permission model, responsible for fine-grained access control based on combinations of subject attributes, resource attributes, and environment attributes. This article details the ABAC attribute model, policy expression engine, implementation of 8 operators, performance optimization of condition evaluation, and coordination mechanisms with the RBAC and ReBAC layers.

CoomiaPublished on September 16, 202511 min read
Share this articleTwitter / X

Series: S6 Platform Engineering · Article 3 | Level: Advanced | Reading Time: 18 min

ABAC Implementation: Attribute-Based Fine-Grained Access Control

#TL;DR

ABAC (Attribute-Based Access Control) is the second layer in coomia-dip's three-layer permission model, responsible for fine-grained access control based on combinations of subject attributes, resource attributes, and environment attributes. This article details the ABAC attribute model, policy expression engine, implementation of 8 operators, performance optimization of condition evaluation, and coordination mechanisms with the RBAC and ReBAC layers.

#1. Core Concepts of ABAC

#1.1 Evolution from Roles to Attributes

RBAC provides indirect authorization through roles, but roles are static. ABAC achieves context-aware authorization through dynamic attributes:

Code
+-------------------+     +-------------------+     +-------------------+
|  Subject Attrs    |     |  Resource Attrs   |     |  Environment Attrs|
+-------------------+     +-------------------+     +-------------------+
| - department      |     | - classification  |     | - time            |
| - clearance_level |     | - owner           |     | - ip_address      |
| - location        |     | - sensitivity     |     | - device_type     |
| - job_title       |     | - data_region     |     | - mfa_status      |
| - certifications  |     | - retention_days  |     | - network_zone    |
+-------------------+     +-------------------+     +-------------------+
         \                       |                       /
          +----------------------+----------------------+
                                 |
                    +----------------------------+
                    |    ABAC Policy Engine       |
                    |   8 Operators for Eval      |
                    +----------------------------+
                                 |
                          ALLOW / DENY

#1.2 ABAC Advantages

DimensionRBACABAC
GranularityRole-levelAttribute-level
DynamismStatic role assignmentReal-time attribute evaluation
Context awarenessNoneTime, IP, device, etc.
Data awarenessNoneClassification level, sensitivity
Policy flexibilityRole combinationsArbitrary attribute expressions
Management complexityLowMedium-High

#2. Attribute Model Design

#2.1 Attribute Classification System

coomia-dip categorizes attributes into four major groups with predefined and custom attributes:

Code
Attribute System
+-- Subject Attributes
|   +-- Identity: user_id, username, email
|   +-- Organization: department, team, division
|   +-- Security: clearance_level, mfa_enabled
|   +-- Role: roles[], groups[]
|   +-- Custom: certifications, specialties
|
+-- Resource Attributes
|   +-- Classification: classification (A1-D)
|   +-- Ownership: owner, project, tenant
|   +-- Metadata: created_at, sensitivity
|   +-- Geography: data_region, storage_location
|   +-- Custom: retention_policy, audit_required
|
+-- Action Attributes
|   +-- Type: action_type (READ/WRITE/DELETE)
|   +-- Bulk: is_bulk_operation
|   +-- Export: is_export
|
+-- Environment Attributes
    +-- Time: current_time, day_of_week
    +-- Network: source_ip, network_zone
    +-- Device: device_type, os, browser
    +-- Auth: auth_method, mfa_status
    +-- Session: session_duration, last_activity

#2.2 Attribute Data Model

PROTOBUF
message AttributeDefinition {
    string name = 1;           // Attribute name: "department"
    string display_name = 2;   // Display name
    AttributeType type = 3;    // STRING, INT, BOOL, LIST, MAP
    AttributeCategory category = 4;  // SUBJECT, RESOURCE, ENV
    bool is_required = 5;
    string default_value = 6;
    repeated string allowed_values = 7;
    string validation_regex = 8;
}

enum AttributeType {
    STRING = 0;
    INTEGER = 1;
    BOOLEAN = 2;
    DOUBLE = 3;
    TIMESTAMP = 4;
    STRING_LIST = 5;
    STRING_MAP = 6;
}

message AttributeValue {
    string name = 1;
    oneof value {
        string string_value = 2;
        int64 int_value = 3;
        bool bool_value = 4;
        double double_value = 5;
        google.protobuf.Timestamp timestamp_value = 6;
        StringList list_value = 7;
        StringMap map_value = 8;
    }
}

#3. Policy Expression Engine

#3.1 Policy Structure

ABAC policies consist of condition expression trees supporting AND/OR/NOT logical combinations:

Code
PolicyRule
+-- effect: ALLOW | DENY
+-- target:
|   +-- subjects: {attribute match conditions}
|   +-- resources: {attribute match conditions}
|   +-- actions: [READ, WRITE]
+-- conditions:
    +-- LogicalExpression (AND/OR/NOT)
        +-- Condition (attribute, operator, value)
        +-- Condition (attribute, operator, value)
        +-- LogicalExpression (nested)

#3.2 Policy YAML Definition

YAML
policy:
  id: "abac-dataset-access-001"
  name: "Dataset Access Control Policy"
  effect: ALLOW
  target:
    resource_types: [DATASET, OBJECT]
    actions: [READ, EXPORT]
  conditions:
    operator: AND
    children:
      - attribute: "subject.clearance_level"
        op: "gte"
        value_ref: "resource.classification_level"
      - operator: OR
        children:
          - attribute: "environment.network_zone"
            op: "eq"
            value: "INTERNAL"
          - attribute: "subject.mfa_enabled"
            op: "eq"
            value: true
      - attribute: "environment.current_time"
        op: "between"
        value: ["08:00", "20:00"]
  obligations:
    - type: MASK
      condition:
        attribute: "resource.sensitivity"
        op: "gte"
        value: "HIGH"
      params:
        mode: PARTIAL_MASK
        fields: ["phone", "email", "ssn"]
    - type: AUDIT
      params:
        level: DETAILED

#3.3 Expression Evaluation Engine

Java
public class AbacExpressionEvaluator {

    private final Map<String, OperatorEvaluator> operators;

    public AbacExpressionEvaluator() {
        operators = Map.of(
            "eq", new EqualityOperator(),
            "ne", new InequalityOperator(),
            "gt", new GreaterThanOperator(),
            "lt", new LessThanOperator(),
            "gte", new GreaterOrEqualOperator(),
            "lte", new LessOrEqualOperator(),
            "in", new InSetOperator(),
            "contains", new ContainsOperator(),
            "matches", new RegexMatchOperator(),
            "between", new BetweenOperator()
        );
    }

    public boolean evaluate(LogicalExpression expr,
                            EvaluationContext ctx) {
        if (expr.isLeaf()) {
            return evaluateCondition(
                expr.getCondition(), ctx);
        }

        switch (expr.getLogicalOperator()) {
            case AND:
                return expr.getChildren().stream()
                    .allMatch(c -> evaluate(c, ctx));
            case OR:
                return expr.getChildren().stream()
                    .anyMatch(c -> evaluate(c, ctx));
            case NOT:
                return !evaluate(
                    expr.getChildren().get(0), ctx);
            default:
                throw new IllegalArgumentException(
                    "Unknown: " + expr.getLogicalOperator());
        }
    }

    private boolean evaluateCondition(
            Condition cond, EvaluationContext ctx) {
        Object actual = ctx.resolveAttribute(
            cond.getAttribute());
        Object expected = cond.isValueRef()
            ? ctx.resolveAttribute(cond.getValueRef())
            : cond.getValue();

        OperatorEvaluator op = operators.get(
            cond.getOperator());
        return op.evaluate(actual, expected);
    }
}

#4. Eight Operators in Detail

#4.1 Operator Implementations

Java
// Equality operator
public class EqualityOperator implements OperatorEvaluator {
    @Override
    public boolean evaluate(Object actual, Object expected) {
        if (actual == null) return expected == null;
        return actual.equals(
            coerce(expected, actual.getClass()));
    }
}

// Set membership operator
public class InSetOperator implements OperatorEvaluator {
    @Override
    public boolean evaluate(Object actual, Object expected) {
        if (expected instanceof Collection<?> set) {
            return set.contains(actual);
        }
        throw new PolicyEvaluationException(
            "IN operator requires collection value");
    }
}

// Regex match operator
public class RegexMatchOperator implements OperatorEvaluator {
    private final Cache<String, Pattern> patternCache =
        Caffeine.newBuilder().maximumSize(1000).build();

    @Override
    public boolean evaluate(Object actual, Object expected) {
        Pattern compiled = patternCache.get(
            expected.toString(), Pattern::compile);
        return compiled.matcher(
            actual.toString()).matches();
    }
}

// Range operator
public class BetweenOperator implements OperatorEvaluator {
    @Override
    public boolean evaluate(Object actual, Object expected) {
        if (expected instanceof List<?> range
                && range.size() == 2) {
            Comparable comp = (Comparable) actual;
            Comparable min = (Comparable) coerce(
                range.get(0), actual.getClass());
            Comparable max = (Comparable) coerce(
                range.get(1), actual.getClass());
            return comp.compareTo(min) >= 0
                && comp.compareTo(max) <= 0;
        }
        throw new PolicyEvaluationException(
            "BETWEEN requires [min, max] array");
    }
}

#4.2 Operator Compatibility Matrix

Code
+----------+--------+-----+------+------+-----------+--------+
| Operator | String | Int | Bool | Time | List<Str> | Double |
+----------+--------+-----+------+------+-----------+--------+
| eq       |   Y    |  Y  |  Y   |  Y   |     Y     |   Y    |
| ne       |   Y    |  Y  |  Y   |  Y   |     Y     |   Y    |
| gt       |   Y    |  Y  |  -   |  Y   |     -     |   Y    |
| lt       |   Y    |  Y  |  -   |  Y   |     -     |   Y    |
| in       |   Y    |  Y  |  -   |  -   |     -     |   Y    |
| contains |   Y    |  -  |  -   |  -   |     Y     |   -    |
| matches  |   Y    |  -  |  -   |  -   |     -     |   -    |
| between  |   Y    |  Y  |  -   |  Y   |     -     |   Y    |
+----------+--------+-----+------+------+-----------+--------+

#5. Attribute Resolution and Collection

#5.1 Attribute Collection Architecture

Code
+-------------------+
| Request Arrives   |
+-------------------+
         |
    +----v----+
    | Attr    |    Collect attributes from multiple sources
    | Collector|
    +----+----+
         |
    +----+----+----+----+
    |    |    |    |    |
    v    v    v    v    v
  JWT  LDAP  DB  Env  Custom
  Attrs Query Query Aware Providers

         |
    +----v----+
    | Attr    |    Merge, validate, cache
    | Context |
    +----+----+
         |
    +----v----+
    | ABAC    |    Policy evaluation
    | Evaluator|
    +---------+

#5.2 Attribute Collector Implementation

Java
@Component
public class AttributeCollector {

    private final List<AttributeProvider> providers;
    private final Cache<String, Map<String, Object>> cache;

    public EvaluationContext collectAttributes(
            AuthenticationContext auth,
            ResourceRef resource,
            HttpServletRequest request) {

        // Subject attributes
        Map<String, Object> subjectAttrs = new HashMap<>();
        subjectAttrs.put("user_id", auth.getUserId());
        subjectAttrs.put("roles", auth.getRoles());
        subjectAttrs.put("department",
            auth.getClaim("department"));
        subjectAttrs.put("clearance_level",
            auth.getClaim("clearance_level"));
        subjectAttrs.put("mfa_enabled",
            auth.isMfaAuthenticated());

        // Resource attributes (cached)
        Map<String, Object> resourceAttrs = cache.get(
            resource.getId(),
            () -> loadResourceAttributes(resource));

        // Environment attributes
        Map<String, Object> envAttrs = new HashMap<>();
        envAttrs.put("current_time",
            LocalTime.now().toString());
        envAttrs.put("day_of_week",
            LocalDate.now().getDayOfWeek().name());
        envAttrs.put("source_ip",
            request.getRemoteAddr());
        envAttrs.put("network_zone",
            classifyNetworkZone(
                request.getRemoteAddr()));

        // Custom attribute providers
        for (AttributeProvider p : providers) {
            p.enhance(subjectAttrs, resourceAttrs,
                envAttrs);
        }

        return new EvaluationContext(
            subjectAttrs, resourceAttrs, envAttrs);
    }

    private String classifyNetworkZone(String ip) {
        if (ip.startsWith("10.")
                || ip.startsWith("192.168."))
            return "INTERNAL";
        if (ip.startsWith("172."))
            return "DMZ";
        return "EXTERNAL";
    }
}

#6. Performance Optimization

#6.1 Short-Circuit Evaluation

Java
// AND expression short-circuit evaluation
public boolean evaluateAndExpression(
        List<LogicalExpression> children,
        EvaluationContext ctx) {
    for (LogicalExpression child : children) {
        if (!evaluate(child, ctx)) {
            return false;  // Short-circuit
        }
    }
    return true;
}

// OR expression short-circuit evaluation
public boolean evaluateOrExpression(
        List<LogicalExpression> children,
        EvaluationContext ctx) {
    for (LogicalExpression child : children) {
        if (evaluate(child, ctx)) {
            return true;  // Short-circuit
        }
    }
    return false;
}

#6.2 Policy Compilation Optimization

Java
public class CompiledPolicy {
    private final Map<String, Pattern> compiledPatterns;
    private final List<Condition> sortedConditions;

    public static CompiledPolicy compile(PolicyRule rule) {
        CompiledPolicy compiled = new CompiledPolicy();

        // Extract and compile all regex patterns
        for (Condition c : rule.getAllConditions()) {
            if ("matches".equals(c.getOperator())) {
                compiled.compiledPatterns.put(
                    c.getValue().toString(),
                    Pattern.compile(
                        c.getValue().toString()));
            }
        }

        // Sort conditions by evaluation cost
        compiled.sortedConditions = rule.getAllConditions()
            .stream()
            .sorted(Comparator.comparingInt(
                CompiledPolicy::estimateCost))
            .collect(Collectors.toList());

        return compiled;
    }

    private static int estimateCost(Condition c) {
        return switch (c.getOperator()) {
            case "eq", "ne" -> 1;
            case "gt", "lt", "gte", "lte" -> 2;
            case "in" -> 3;
            case "between" -> 4;
            case "contains" -> 5;
            case "matches" -> 10;  // Regex is most expensive
            default -> 5;
        };
    }
}

#6.3 Performance Benchmarks

ScenarioAvg LatencyP99 Latency
Simple eq condition (1-2)0.1ms0.5ms
Compound AND (3-5)0.3ms1.2ms
Nested AND/OR (5-10)0.8ms3.5ms
With regex match1.5ms6.0ms
With attribute value ref1.2ms5.0ms

#7. Practical Policy Examples

#7.1 Work Hours Restriction Policy

YAML
policy:
  id: "abac-time-restriction"
  name: "Work Hours Data Access Restriction"
  effect: DENY
  conditions:
    operator: AND
    children:
      - attribute: "resource.classification"
        op: "gte"
        value: "B2"
      - operator: OR
        children:
          - attribute: "environment.current_time"
            op: "lt"
            value: "08:00"
          - attribute: "environment.current_time"
            op: "gt"
            value: "20:00"

#7.2 Geo-Fencing Policy

YAML
policy:
  id: "abac-geo-fence"
  name: "China Data Restricted to Domestic Access"
  effect: DENY
  conditions:
    operator: AND
    children:
      - attribute: "resource.data_region"
        op: "eq"
        value: "CN"
      - attribute: "environment.source_country"
        op: "ne"
        value: "CN"

#7.3 Security Clearance Matching Policy

YAML
policy:
  id: "abac-clearance-match"
  name: "Security Clearance Matching"
  effect: ALLOW
  conditions:
    operator: AND
    children:
      - attribute: "subject.clearance_level"
        op: "gte"
        value_ref: "resource.classification_level"
      - attribute: "subject.department"
        op: "in"
        value_ref: "resource.allowed_departments"

#8. Coordination with RBAC and ReBAC

#8.1 Evaluation Order

Code
Request -> [RBAC Fast Path] -> [ABAC Refinement] -> [ReBAC Check]
                |                      |                    |
          Fast allow/deny       Condition eval        Graph traversal
                |                      |                    |
                +----> DENY-overrides merge <--------------+

#8.2 ABAC Augmenting RBAC Pattern

Code
Scenario: DATA_ANALYST has READ permission (RBAC ALLOW)
          but needs ABAC further constraints:

RBAC: DATA_ANALYST -> READ -> DATASET    (ALLOW)
ABAC: + classification < C1             (Condition 1)
      + network_zone = INTERNAL         (Condition 2)
      + time between 08:00-20:00        (Condition 3)

Final: Allow only when all ABAC conditions are satisfied

#9. Policy Management

#9.1 Policy Version Control

Code
Policy change workflow:
  1. Write policy YAML
  2. Policy validation (syntax, attribute refs, type checks)
  3. Impact analysis (simulate against existing requests)
  4. Approval workflow
  5. Canary release (verify in test environment first)
  6. Full release
  7. Monitoring and alerting

#9.2 Policy Simulation

Python
from ontology_sdk import OntoPlatform

platform = OntoPlatform(endpoint="grpc://control-Layer:9090")

simulation = await platform.policy.simulate(
    policy_id="abac-dataset-access-001",
    test_cases=[
        {
            "subject": {"clearance_level": "B3",
                        "department": "engineering"},
            "resource": {"classification": "B2",
                         "type": "DATASET"},
            "environment": {"time": "10:00",
                            "network_zone": "INTERNAL"},
            "expected": "ALLOW"
        },
        {
            "subject": {"clearance_level": "A2",
                        "department": "marketing"},
            "resource": {"classification": "C1",
                         "type": "DATASET"},
            "environment": {"time": "22:00",
                            "network_zone": "EXTERNAL"},
            "expected": "DENY"
        }
    ]
)

for result in simulation.results:
    print(f"Case: {result.case_id}, "
          f"Decision: {result.decision}, "
          f"Match: {result.matches_expected}")

#10. Monitoring and Alerting

#10.1 ABAC Evaluation Metrics

MetricDescriptionAlert Threshold
abac_evaluation_duration_msEvaluation timeP99 > 10ms
abac_evaluation_totalTotal evaluations-
abac_evaluation_deny_rateDeny rate> 40%
abac_attribute_resolution_errorsAttr resolution errors> 0
abac_policy_compilation_errorsPolicy compilation errors> 0
abac_cache_hit_ratioAttribute cache hit rate< 60%

#Key Takeaways

  1. Four attribute categories: Subject, resource, action, and environment attributes provide unlimited flexibility for authorization expressions
  2. 8 operators cover equality comparison, range checks, set membership, regex matching, and all enterprise-grade requirements
  3. Expression trees support AND/OR/NOT nesting to express arbitrarily complex policy logic
  4. Short-circuit evaluation and policy compilation optimization ensure sub-millisecond evaluation performance
  5. Attribute value references allow conditions to reference other attributes (e.g., subject.clearance >= resource.classification)
  6. Policy simulation capability makes policy changes safe and controllable

#Next Article

The next article S6-04: ReBAC Implementation: Relationship-Based Access Control (Like Zanzibar) will explain how coomia-dip draws from Google's Zanzibar paper to implement relationship-based access control through relationship tuples and graph traversal.

Tags: #ABAC #AttributeAccessControl #PolicyEngine #Operators #FineGrainedPermissions #ExpressionEngine #coomia-dip #PlatformEngineering #Security #Palantir