On Roles and Entitlements

April 10, 2008

The prometheus group system is based around two primitives – the role and the entitlement. We’ve been using a similar system in Informatics for years (we called entitlements “capabilities” – a term we’re trying to move away from, as a capability has a very specific meaning in authorisation literature). Simply put, a role is something you are (a person, a member of staff, a system administrator) and an entitlement is something that you can do (access webmail, log in to the compute cluster, edit the DNS).

A role contains a list of entitlements that having that role conveys upon that user (for example, the system administrator role might convey the “edit the DNS” entitlement). In addition, roles may contain other roles (a member of staff is also a person), in which case a user with that role also gains all of the entitlements (and roles) from the referenced role. Users may also be granted entitlements directly – this is implemented primarily to remove the need to create eponymous roles for single entitlements.

Services perform access control by checking a users possession of the appropriate entitlement.

In prometheus, roles and entitlements are represented as LDAP objects, with DN-valued attributes modelling the links between them. Entitlements maintain LDAP groupOfNames style lists of identities with that particular entitlement. In the current production DICE system entitlements are also made available as netgroups and, in a small number of cases, Unix groups. With prometheus, these additional entries will be produced through the conduit system into the production LDAP directory.

A diagram might make all of that a little clearer …

Roles and Entitlement Relationship Diagram

This shows a user, who has been given two roles (A & B), and who gains roles C and D through inheritance. The user gains a set of entitlements both through these roles, and also gains entitlement D by direct reference from the user object. I’ll come back to this layout as I discuss some of the challenges of maintaining this model.

The system has to convert this layout (and one containing many more users!) into a list, within each entitlement, of all of the users who have that entitlement. These lists have to be consistently maintained across all possible changes to the set of roles and user objects. Our current implementation performs this maintenance by regularly rebuilding the entire set using an external perl script. This results in significant propagation delays, as well as requiring a large amount of potentially unnecessary computation.

Complication 1: Negative Entitlements

The original proposal documents permit the creation of negative entitlements. A negative entry for a particular entitlement in a role, or user entry, blocks the user’s receipt of that entitlement, regardless of execution ordering. Any automatically generated entitlement list needs to take into account negative entitlements.

Implementation Issues

None of the OpenLDAP dynamic group, or memberOf, tools have sufficient power to solve this problem. memberOf comes close, but doesn’t have the nested group support we would require to evaluate down the entire tree. Even if member-of acquired nested group capabilities, it would still not be able to handle negation. So, any implementation is going to have to use custom tools. There are a number of options

  • An independently triggered script which responds to applicable resource changes, and rebuilds the entire tree. This could be implemented as a prometheus conduit, and moves capability processing completely out of the main server loop. Pros are that this is relatively easy to implement, and it adheres to the prometheus model. Cons are that it adds an external dependency for ACL changes, and that it makes it impossible to reject changes which introduce loops when they are initially committed to the directory.
  • An overlay which extends the current memberOf directive to support in-server updating of the entitlements list. Pros are that this would make it possible to reject changes which introduce loops, or break links, immediately they occur. Cons are that it is a significant body of code which would be running inside the directory server.

Regardless of the implementation mechanism, the question arises of how we perform the updates. The simplest way is to rebuild the entire tree with every change, but as noted earlier this is slow, and inefficient. A more efficient approach is to simply rebuild those sections of the tree which have been changed by the latest update. However, performing incremental changes without locking is really tricky. If we’re trying to rebuild the minimum in response to a change, then that requires that we know the state of the tree at the point that that change occurred. Both in, and out-of, directory solutions have the problem that other modifications may occur between the change, and us checking the state of the tree. An in-directory solution might be able to lock the tree in some way to queue further write actions behind it, but that’s a scary prospect.

More thought on this is definitely required. Initially, the temptation is to use an external rebuild everything on every change script, as that can be simply prototyped from the one currenly in use. As the project progresses it will be possible to experiment with better solutions.

Update on the way to dinner: A further thought that needs to be integrated into the above, is that roles and entitlements are just special types of nested group. A role is an internal group (that is, one which is actually nested), and an entitlement is a leaf group (that is, one at the edge of the tree, that contains no other groups). A memberof operator that works on nested groups would solve many of the problems outlined above.


March 26, 2008

Seeing as I seem to have stalled in publishing the ‘vision’ documents I talked about earlier, here’s something more concerned with implementation nitty gritty: password handling.

In the wild, there appear to be three main approaches to handling passwords with an identity management system…

  • Password syncronisation. In this model, the password field is just like any other attribute. A master copy is stored within the identity management system, and syncronised with each database it feeds. Changes are propagated using the standard attribute management mechanisms. This has the obvious security drawback that the account management system must hold a plaintext copy of every user’s passwords, and is therefore a pretty critical bit of infrastructure.
  • Initial passwords. As its position on this list suggests, this is a half-way house. Instead of storing passwords for every user, the identity management system stores an ‘initial password’. This is used to populate the password field of a user when an entry is created in a subscribing database, but further changes are not mirrored in either direction. Any password syncronisation which occurs does so without the identity management system’s participation or knowledge
  • No passwords. This model gives the account management system no knowledge of passwords at all. When new entries are created in subscribing databases, the syncronisation script is responsible for setting a password of its choice (typically a random one). All password management operations take place outside of the management system.

Each of these schemes has its drawbacks, and the intention is that prometheus will be capable of supporting all three.

And now, for the DICE specific bit. The issue for us here is one of workflow. Currently, an account isn’t “created” until a manual step is performed to take the account details out of the Divisional Database, and populate LDAP, Kerberos and the like. With prometheus, the account management system will be populated with all accounts that exist in the database, and the presence/absence of entitlements and roles will be all that stops them from being full blown accounts. Prometheus has to be able to handle the case where these entitlements appear automatically (perhaps even as a result of settings in the database). This means that there is no longer a human involved in the creation step, and so no way of setting a password, or even telling it which printer the password letter should come out of. 

The solution to this will be to make the create account script be simply one which sets a password (it may also ensure the presence of various entitlements). In order to make this as portable as possible, we need to know for a given account where the password should be set – so there will be a prometheusPasswordStore field in LDAP, which contains a list of perl modules implementing Prometheus::PasswordStore which should be called with the users password when its changed through this script.

Similar technology could be used to maintain initial passwords when using the 2nd model. When the 1st model is in use, the password need only be updated within the prometheus LDAP store – however, this means we need to ensure that the frontends have code for managing password fields, even if our local implementation doesn’t use them.

Distributed Access

February 6, 2008

One of my key criticisms of our current Account Management system, and of many of the other account/identity management products on the market is the high degree of centralisation that they require. When you distribute out service management, you need an account management system that can provide a similar level of distribution of provisioning. It shouldn’t be necessary for every provisioning script to be built into the runtime of the central system (as with our current system). It shouldn’t even be necessary that every provisioning script to run on the same central server. It really shouldn’t be necessary that provisioning scripts be developed and maintained by the people who run the account management system.

Some of these concerns come from scalability. Experience has shown that requiring that changes be made to the central account management system every time a new service is deployed doesn’t scale in terms of developer time. The priorities of a team deploying a new service often don’t mesh with those managing the central system, and requiring that a developer have an in depth knowledge of both the central management system, and the account database of the new service can cause difficulties. Eventually, you end up with a central system that, no matter how well designed the plugin architecture is, is creaking with the load of all the services hanging off it.

This model also causes problems with delegation. I’ll talk more about delegation in a later post, but part of the delegation issue is also pertinent here. In a model where more and more ‘services’ are being managed by research groups, it’s just not realistic to require that deployment of one of these new services requires changes to the central provisioning system.

Instead, a truly distributed account management system should move the provisioning details away from the centre, and locate it locally to the service. This doesn’t necessarily mean that the provisioning is performed on the machine(s) the service runs on, but that conceptually the provisioning act is the responsibility of those managing that service, and not of those running the central system.


January 24, 2008

This blog is going to accumulate a selection of musings about the design and build process for Prometheus, the School of Informatics’ new account provisioning system. They’re going to form a historical record of the thinking behind Prometheus’s system architecture, and its implementation. This historical record means that what’s written before will be superseded by what’s written afterwards. A post’s tags will indicate the general area of discussion – other posts with the same tag may update, or even replace the contents of earlier posts. Posts will also be split into categories – with the design category covering system design issues, and implementation going into the nitty gritty of how things work I’m going to kick off with a series of posts about some core elements of Prometheus… 

  • Distributed Access
  • Delegation Everywhere
  • Push vs Pull
  • The KISS principle

And then about some design decisions that these inform

  • LDAP everywhere