TypeDB Blog


Identity and access management with TypeDB: Part III, inference

In the last two blogs, we learned how to model polymorphic permissions and automate permission inheritance. Now, we’ll finish this blog series by explaining how to enforce policy compliance at the schema level.

James Whiteside

·


In this blog series, we explore how TypeDB can meet all the requirements for a federated identity and access management (IAM) platform with a lean data model and intuitive query design. The primary focus will be on a role-based access control (RBAC) architecture, but our approach can be easily adapted to other frameworks.

In the last two blogs, we learned how to model polymorphic permissions and automate permission inheritance. Now, we’ll finish this blog series by explaining how to enforce policy compliance at the schema level.


We’ve seen how TypeDB implements a logical data model, allowing us to create a powerful schema with type inference and apply business logic using rule-based inference. Now let’s try something a bit more complicated by implementing a common but tricky requirement of IAM platforms: segregation-of-duty policies. In short, a segregation-of-duty policy defines two actions (or duties) that should never be performed by the same person, for example submitting a purchase order and approving it. To begin with, let’s define a new segregation-policy relation:

define

segregation-policy sub relation,
   relates action,
   owns name;

action plays segregation-policy:action;

Next, let’s insert the policy for our independent purchase order approval:

match
  $a1 isa operation, has name "submit order";
  $a2 isa operation, has name "approve order";
insert
  ($a1, $a2) isa segregation-policy, has name "independent order approval";

That’s great, but how do we go about enforcing it? First off, we need to keep track of who’s submitted which purchase orders, or more generally, which permissions have been exercised. To do this, we’ll add a new relation type to our schema:

define

access-history sub relation,
  relates subject,
  relates access,
  owns access-time;

subject plays access-history:subject;
access plays access-history:access;

access-time sub attribute, value datetime;

The access-history relation has the same role players as a permission. This means that, whenever a permission is exercised, we can insert an access history relation between the permission’s role players, then attach the access time as an attribute. Next, we need a way of invalidating permissions, so we’re going to add a new attribute:

define

validity sub attribute, value boolean;

permission owns validity;
Entity types (pink) and relation types (yellow) in the schema so far.

We don’t really want to be keeping track of which permissions are valid or invalid. Luckily, we can automate it all with rule-inference. Let’s define a couple of new rules:

define

rule automatic-permission-invalidity:
   when {
       ($a1, $a2) isa segregation-policy;
       $ac1 ($a1, $o) isa access;
       $ac2 ($a2, $o) isa access;
       ($s, $ac1) isa access-history;
       $p ($s, $ac2) isa permission;
   } then {
       $p has validity false;
   };

rule automatic-permission-validity:
   when {
       $p isa permission;
       not { $p has validity false; };
   } then {
       $p has validity true;
   };

This pair of rules will automatically generate validities for every permission based on whether or not that particular permission violates a segregation policy. Let’s look at an example. We’ve already given the Finance Department permission to approve purchase orders, so let’s now give them permission to submit them too:

match
  $s isa business-unit, has name "Finance";
  $o isa application, has name "Sage";
  $a isa action, has name "submit order";
  $ac ($o, $a) isa access;
insert
  ($s, $ac) isa permission;

Now let’s say that Amos Burton, a member of Finance, wants to submit a new purchase order with the reference MCRN-01. In order to check if he can, we execute the following query:

match
  $s isa employee, has email "[email protected]";
  $o isa purchase-order, has reference "MCRN-01";
  $a isa action, has name "submit order";
  $ac ($o, $a) isa access;
  ($s, $ac) isa permission, has validity true;

Because of the permission inheritance we set up earlier, this successfully returns a result, indicating that Amos has the required permission and allowing him to submit the order. When he does so, the following query is triggered to store the fact that he exercised that particular permission:

match
  $s isa employee, has email "[email protected]";
  $o isa purchase-order, has reference "MCRN-01";
  $a isa action, has name "submit order";
  $ac ($o, $a) isa access;
insert
  ($s, $ac) isa access-history;

He then attempts to approve that same order, which triggers the following query:

match
  $s isa employee, has email "[email protected]";
  $o isa purchase-order, has reference "MCRN-01";
  $a isa action, has name "approve order";
  $ac ($o, $a) isa access;
  ($s, $ac) isa permission, has validity true;

However, this fails to return any results because TypeDB has flagged Amos’ permission to approve purchase order MCRN-01 as invalid according to the segregation policy we defined. Amos is still free to approve other purchase orders, and anyone else can approve order MCRN-01, but Amos is blocked from approving this particular purchase order because of rule inference. While that might seem like the obvious response to his approval attempt, it’s actually inferred through a complex series of steps. Let’s dig a bit deeper into the facts that we provided to TypeDB:

  • No user is able to both submit and approve the same purchase order.
  • Orders can be submitted through the Sage platform.
  • Orders can be approved through Sage.
  • The Finance Department can submit orders through Sage.
  • Finance can approve orders through Sage.
  • Amos Burton is a member of Finance.
  • The purchase order with reference MCRN-01 is on Sage.
  • Amos Burton submitted order MCRN-01.

By combining these facts with the rules we encoded into the schema, TypeDB is able to generate the following new facts without any further input:

  • Amos Burton is permitted to submit orders through Sage.
  • Amos Burton is not permitted to approve order MCRN-01.
  • Amos Burton is permitted to approve other orders through Sage.
  • Other members of Finance are permitted to approve order MCRN-01.

Not only that, these inferred facts are generated at read-time so they’ll never be stale. This means the moment a segregation policy is violated, the relevant permissions are instantly invalidated by the rules. There is never a time at which a permission has an incorrect validity because the validity of each permission is never written to the database. Here we’ve ensured 100% compliance with any segregation-of-duty requirements we define by implementing the business policies at the database level, and it’s pretty easy to extend this to other business policies as well.


We’ve seen how we can use TypeDB as the database for an IAM platform. By leveraging TypeDB’s subtyping, type inference, polymorphism, dependent types, and rule inference, we can build an extensible schema that’s queried with near-natural language, automate permission inheritance by abstracting business logic out of our queries, and enforce airtight compliance with business policies by taking advantage of a built-in reasoning engine. And all of these features are only scratching the surface. With the highly extensible subject, object, and action hierarchies, many more relations can be defined that capture even more complex aspects of IAM. Try it for yourself by running our interactive demo, or learn more about building IAM platforms on TypeDB by reading our white paper.

Entity types (pink) and relation types (yellow) in the schema available in the demo.

Share this article

TypeDB Newsletter

Stay up to date with the latest TypeDB announcements and events.

Subscribe to Newsletter