What's wrong with the ANSI RBAC standard? Part 3 - what happens when you remove an inheritance relationship?
By jeff.shukis on Aug 15, 2008
The ANSI standard for RBAC (ANSI 359-2004) includes role hierarchies as an optional feature. The model of role hierarchies defined is simple, easy to understand, and generally good stuff. It does have a few problems, one of which I think should be addressed: When in a role hierarchy an inheritance relation between two roles is removed, the specification doesn't say what should happen. It should. There are two possible behaviors in theory. In a world where workflow, approval, and attestation are important - our world - there is really only one good behavior.
A role hierarchy consists of roles related to each other with binary inheritance relations. A role that inherits from another role effectively adds all of the permissions of the first role to its own permission set. Role grantees are also inherited, but today’s discussion will focus on the inheritance of permissions.
Let’s construct a simple scenario. Imagine an existing role, R1 that is the root of a role hierarchy. R1 contains 100 directly assigned permissions. In text form we can diagram this as: (R1). See Figure 1 below for a prettier version.
Figure 1 - Role Hierarchy with only one role
Now imagine a role R2 that inherits from R1 and adds 10 of its own permissions. Including inherited permissions, R2 has 110 authorized permissions; authorized permissions being the sum of directly granted permissions and inherited permissions. Figure 2 below shows this minimal role hierarchy in graphic form. In text form we say:
(R2 --> R3)
Figure 2 – Role R2 added to the role hierarchy
I now add a new role R3 with one direct permission and declare that it inherits from R2 as shown in Figure 3 below. Figure 3 also fills in the role hierarchy with a few more roles that aren’t necessary for our scenario but better emphasize the notion of a role hierarchy. R3 will have 111 authorized permissions – one direct permission and 110 permissions inherited from R2, which in turn inherited 100 of its 110 permissions from R1. In text form the inheritance chain looks like this, with R2 in the middle position:
(R3 --> R2 --> R1)
Figure 3 - Completed role hierarchy
Notice that R3 inherited 10 Permissions from R2 because of the direct inheritance relation between these roles. Now note that R3 also inherited Permissions from R1 - but not directly. It inherited Permissions from R2, which inherited some from R1. One way of describing this is as indirect inheritance. It is as if an invisible relation exists between R3 and R1 as shown in figure 3b below. Side note: In any software implementation, this implied relation probably actually exists since doing so makes the inheritance calculations much faster!
Figure 3b – Indirect inheritance relation visualized via a dotted line
Now imagine that someone else begins to edit the role hierarchy. They remove (via the role management application UI) the inheritance relation between R2 and R1 as shown in Figure 4 below.
Figure 4 - Removing the R2 --> R1 inheritance relation
When this happens, it is easy to see what should happen to the permission set of R2: With the inheritance relation gone, R2 loses the 100 inherited permissions, leaving just its 10 directly assigned permissions. What isn’t obvious is what should happen to R3. Should R3 lose the 100 Permissions that it indirectly inherited from R1 or should it keep them? Should our simple UI action have the effect of completely reworking the role hierarchy or just gently snipping away part of it?
Some say that removing an explicit inheritance relation should remove any implied inheritance relations - rebuild the role hierarchy, they say, and let R3 lose all inherited Permissions. Let's call this simply Approach One - see the left half of Figure 6 below. In text form, this approach yields: Approach One: (R3 --> R2).
Approach Two (shown on the right of Figure 6) is one in which we preserve implied inheritance. In text form, this yields Approach Two: (R3 --> R1, R3 --> R2).
Figure 4 - Remove indirect inheritance (Approach One - left) or preserve it (Approach Two - right)
There are very good arguments for each approach:
The argument for using Approach One is Simplicity. The Remove Implied Inheritance approach shown on the left side of Figure 6 is the easiest to understand of the two. The action of removing the inheritance relation between R2 and R1 results in the removal of that relationship and all implied/invisible relations that it created. R3 continues to inherit from R2 but no longer inherits from R1. This approach is nicely symmetrical – creating an inheritance relation by necessity creates implied relations, removing the inheritance relation neatly removes those implied relations.
Unfortunately, this very appealing symmetry can be troublesome in an environment where administration is distributed. For example, the 111 carefully chosen permissions of my carefully managed role R3 get decimated because someone else removed an inheritance relation between two different roles over which I don’t necessarily have any control or influence. Before that other user removed the relation, my role had 111 permissions. Afterward, it has just 11 – and there’s not much that I can do about it except fix my role manually afterward. Suddenly, this approach is not looking nearly as appealing. Hopefully Approach Two is better.
Approach Two, the Preserving Implied Inheritance approach, is a bit more complex than Approach One but specifically addresses the problem we found above. When I created R3, I knew that I needed 111 permissions. Noticing that R2 already had 110 of them, I decided to create an inheritance relationship instead of defining my role from scratch. When someone else deleted the R2 to R1 inheritance relation, that didn’t mean that I no longer needed all 111 permissions in my R3. What happens in Approach Two, therefore, is that when the explicit inheritance connection between R2 and R1 is deleted, the system acts to preserve my earlier intentions by converting the implied inheritance relation (dashed line in Figure 3b above) into a new explicit inheritance relation. R2 is effectively “snipped out of” the prior inheritance chain, altering its inheritance (as desired) but leaving the other roles in the hierarchy unchanged by its removal. After this change, R3 continues to have 111 permissions as before – one directly, 10 remaining from the inheritance relation with R2 and 100 formerly indirectly inherited but now directly inherited. This can be pictured as (R3 --> R1, R2 --> R1) with R2 removed from the hierarchy. The right hand side of Figure 6 above shows a prettier picture of our role hierarchy after the change using Approach Two.
Which approach is the right one? In the published standard, this question is left entirely open. I can easily imagine each school of thought arguing in favor of its idea until some wise person eventually decided to simply leave the question unanswered in order to get the final specification published. As we know, however, standards that leave key behaviors unspecified can come back to bite us.
I happen to think that there is only one workable approach among the two. It is possible to home in on that one approach by expanding our scenario to include basic notions of distributed administration, auditing, and workflow and then re-evaluating each approach within the expanded scenario.
When I created the inheritance relation between R3 and R2, my action was subject to an access control check and, probably, a workflow and approval process. The access control check verified that I had the right to create an inheritance relation between these specific roles. The workflow and approval allowed a third party to review and approve my action. The audit system then recorded my action and its approval for later use - perhaps in an attestation report. When the other user removed the inheritance between R1 and R2, their action was similarly checked, approved, and audited.
These access checks, approvals, and audit records are why Approach Two, which preserves implied inheritance, won't work in practice. If, as described for Approach Two, all 111 permissions are retained in R3 after the change by automatically creating a new inheritance relation between R3 and R1, whose authorization was checked when the relation was created? In the audit record, who is recorded as having created the relation and who as having approved it? If the “system” did the work then we have a definite lack of accountability. If the person who removed the inheritance relation between R1 and R2 did it, then giving the user the right to remove inheritance relations also gives them the right to create new relations between sometimes wildly unrelated roles – clearly undesirable. My conclusion is that an approach that preserves implied inheritance relations, while appealing, untenable in our distributed, workflow-centric, audited world.
If the second approach is unworkable, then that leaves the first. Fortunately, access control, audit, and workflow do not cause unintended consequences with this approach given it’s symmetry. Unfortunately, there are still those undesirable consequences – such as the fact that someone who removes an inheritance relation between two roles can cause dramatic changes to the permissions authorized for other roles that the person probably could not edit directly. These behaviors do not appear to be unworkable, but they do deserve further discussion – just not today.
There are also two other “alternative” approaches that have not previously been discussed in the industry, one of which just might work. Unfortunately, I’m out of time and will have to leave that discussion for another day. I’d also like to explore the case for separating Permission inheritance from user inheritance.
Q: What are your thoughts on role hierarchies in general and this topic specifically?