Method Madness

"Though this be madness, yet there is method in't."
Polonius, Hamlet Act 2, scene 2

Introduction

The main point of contention in the ACL debate seems to centre around the mechanism used to permission non AMQP entities, the current METHOD method is felt to be unsuitable. This document proposes an update to this syntax and describes exactly how it should be interpreted across brokers.

Access Control

The things that are being controlled or permissioned by entries in the access control list are objects that form part of the Qpid broker. These entities could reasonably be said to be children of the broker, although I don't feel that a tree-type structure is either helpful or necessary here, since there is no parallel in the Qpid or AMQP internals. A flat object type space has therefore been assumed, continuing current behavior. These types of object have until now simply represented the major types of object that exist and are manipulable inside a broker. The only addition is that of the broker itself, since there are some operations and actions that can only realistically be said to be performed globally. This is the rationale behind such proposed ACL entries as:

ACL ALLOW robot ACCESS LOG
ACL DENY robot UPDATE CONFIG
ACL DENY kitten UPDATE USERS
ACL ALLOW kitten ADMIN LOG

The LOG, CONFIG and USERS object types here represent subsystems or components or simply collections of management methods that perform a similar set of tasks. They are not actual broker objects, although (see later) they may be QMF classes, with their own management schema and package.

A different approach to access control for these management methods relies on the BROKER object type being used for permissioning, giving rise to ACL entries as follows:

ACL DENY robot ACCESS BROKER
ACL DENY kitten UPDATE BROKER subsystem=logging
ACL ALLOW kitten ACCESS BROKER method=get*
ACL ALLOW kitten ACCESS BROKER method=invoke*
ACL ALLOW kitten MANAGE BROKER subsystem=users

This BROKER object type represents the entire runtime entity, and is in fact represented in the QMF management schema, with properties, statistics and methods available. This is not meant to indicate a preference for QMF as a final reference point, it should be noted, rather this is illustrative of the sorts of entities an access control object type could map to.

<class name="Broker">
    <property name="name" />
    <property name="systemRef" />
    <property name="port" />
</class>

Existing Syntax

The previous ACL entries would all be permissioned using the METHOD object type in the current C++ broker, assuming a logical extension of the existing syntax. The problem with this syntax is that it is very closely coupled to the management framework, QMF. Also, the granularity of the controls falls awkwardly between extremes, and requires too much specificity to enumerate all methods dealing with a particular area of interest when controlling that type of access, and not distinguishing between getName methods on various different managed objects. This makes it impossible to correctly permission access to multiple objects with similarly named methods. Also, since JMX provides access to properties using a method call, a permission for that method would need to be created to allow READ access to a property, which blurs the distiction between methods and properties.

Mechanism versus Meaning

Since the current C++ implementation is based exclusively on QMF, only features supported and used by QMF are available. It is preferable to have a mechanism-agnostic access control specification, since QMF and JMX will not be the only management entry-points for ever, with SNMP and other industry standards available as well as future JEE development. Also, it should be possible to permission access in a manner that does not depend on the version of the QMF schema or API, depending only on the existence or not of particular manageable objects within the broker. This means that when a new method or attribute is added at an API change, or a method name is changed, existing ACLS will have the same meaning as before. This semantic preservation is the aspect of the ACLs that is most important.

The existing object types all relate to the Qpid broker objects, and the best way to move forward is to maintain that relationship, and ensure that all operations have the correct meaning and are controlled correctly in the broker, no matter how they are accessed. This means that an ACCESS QUEUE ACL entry would entail granting permission to view the properties of a queue via the QMF console, via a JMX console utility or the JMX API and by interrogating the queue over JMS or through the C++ AMQP client.

Operational Constraints

The ACCESS operation is assumed here to map to some kind of read-only access. Typically in a software management system the following three types of operation are available:

  • Read - Access the contents of an attribute, statistic or property.
  • Write - Set the contents of an attribute or property.
  • Execute - Call a method or take an action or operation.

It is proposed that the existing operations are maintained, along with the mappings to object types they are allowed to manipulate (as described in a previous text) and the three types described above are mapped as follows:

  • ACCESS - Read
  • UPDATE - Write
  • EXECUTE - Execute

ACCESS continues to describe simple, read-only property or attribute access, mapping nicely a JMX intent of INFO or a get type of operation. UPDATE would be used for read-write access to properties, when the operation carried out is a simple change of value with no side effects. The new EXECUTE operation replaces the contentious ADMIN or MANAGE described previously, and more accurately describes the execution or invocation of an administrative action or operation with a particular effect on the broker.

Brokerage

The BROKER object type is to be used to control access to any new set of features. For example, if it is desired to add an ACL entry that will allow the robots group to read and write properties on the Acl QMF managed object, and additionally to execute all methods that are present, this could be done as follows:

ACL ALLOW robots ACCESS BROKER package="org.apache.qpid.acl"
ACL ALLOW robots UPDATE BROKER package="org.apache.qpid.acl"
ACL ALLOW robots EXECUTE BROKER package="org.apache.qpid.acl"

If a logging subsystem was added, with the QMF management schema package defined as org.apache.qpid.log and methods such as setLoggingLevel, getAvailableLoggingLevels, reloadLogFile, rollLogFile are defined, along with properties like currentLevel and lastLogEntryTime then it could be permissioned this way:

ACL ALLOW robots ACCESS BROKER package="org.apache.qpid.log"
ACL ALLOW robots UPDATE BROKER package="org.apache.qpid.log"
ACL ALLOW kitten EXECUTE BROKER package="org.apache.qpid.log" method="rollLogFile"
ACL ALLOW robots EXECUTE BROKER package="org.apache.qpid.log" method="reloadLogFile"
ACL DENY robots EXECUTE BROKER package="org.apache.qpid.log" 

In this example, the robots group can only execute reloadLogFile while kitten (a member) can also execute rollLogFile, and the group has read/write access to all properties and statistics. It should be obvious that there is scope for adding arbitrary new packages and then permissioning them. Also, if the contents of the packages are well defined and they are suitably finely grained then it will mostly suffice to permission at the package level for all operations and properties. This gives freedom to update APIs and add new methods without making ACL files obsolete or causing security issues, since the meaning of the ACL entries should be unchanged.

Care will need to be taken with, for example, JMX invoke method, which offers a level of indirection that could enable bypassing access checks. This is currently handled at a common JMX entry point, and should suffice at present.

Syntactic Sugar

In an attempt to divorce the ACL syntax from the mechanism further, it could also be possible to remove references to the package and use a different naming scheme, which would have a mapping to QMF, JMX managed objects and any future management information repository. This could work as follows, with users mapping to the JMX UserManagement MBean and a QMF org.apache.qpid.users package with a Users class. The change to the ACL syntax is trivial. Additionally, changing all properties to simply name would standardise the syntax further, with only a small loss of readability.

ACL ALLOW kitten EXECUTE BROKER component="users" name="*"
ACL ALLOW kitten UPDATE BROKER component="users" name="fileName"

It is possible that another object could be chosen instead of BROKER, such as METHOD (however this gives the issue of changing the meaning of existing files) but this would not change the discussion presented above. The only issue might be that it is cumbersome to add a permission granting access to all management methods, properties and statistics, both read and write, at the same time. Even though UPDATE will usually include ACCESS permissions, two lines are needed (for EXECUTE separately) unless it is satisfactory for EXECUTE to include UPDATE (and hence ACCESS) rights.

ACL DENY robot EXECUTE METHOD component="config" name="reload*"
ACL ALLOW kitten ACCESS METHOD component="config" name="*"

It could be pointed out that ACCESS METHOD ought more correctly to read ACCESS PROPERTY and similarly for UPDATE, however it is felt that the number of object types should be kept to a minimum, which is the purpose of this proposal.

Conclusion

The ACL changes described above are fairly simple, but should provide a sensible and easily extensible syntax that will allow both the Java and C++ brokers to provide fine grained access control for custom components that are specific to each implementation without compromising cross- platform file compatibility. The actual access and management mechanisms for the brokers do not impact the ACL syntax, which remains agnostic, and also maintains its meaning through API upgrades and extensions without compromising platform security.

There are several options for ACL file syntax describing access to methods controlling a (for example) logging mechanism, which are summarised below:

  • Extra object type created for each set of management methods, with unique per-object set of properties. This is the least extensible mechanism.
ACL ALLOW kitten EXECUTE LOG
  • Specify all method names to be permissioned as in the current C++ broker implementation, using METHOD as the object type. This does not allow property access to be permissioned or prevent name clashes in different managed object classes.
ACL ALLOW kitten UPDATE METHOD name="methodNameOne"
ACL ALLOW kitten UPDATE METHOD name="methodNameTwo"
  • Use BROKER or METHOD object type and specify the component or subsystem by an arbitrary name, with the option to specify down to individual methods by adding a wildcarded name pattern. Using METHOD in this way is close to the current C++ syntax. Alternatively, the QMF package name could be used to identify the component. Different operations are used to describe access to properties or attributes.
ACL ALLOW kitten EXECUTE BROKER subsystem=logging
ACL ALLOW kitten EXECUTE BROKER package="org.apache.qpid.log"
ACL ALLOW kitten EXECUTE METHOD component="log" name="reload*"
ACL ALLOW kitten UPDATE METHOD component="log"
ACL ALLOW robot ACCESS METHOD component="log"
ACL ALLOW robot EXECUTE METHOD component="acl" name="reload*"
ACL DENY robot EXECUTE METHOD component="config" name="reload*"
ACL ALLOW robot EXECUTE METHOD component="config"

The last described syntax is close to a preferred option, and incorporates features from recent dev.qpid.apache.org discussion, although any updates or suggestions are welcome.

(Note this has the interesting/useful feature/bug of falling back to C++ broker syntax if the component property is omitted. This would be legal in the Java broker, just not recommended.)

Post Scriptum

The following points should clarify some of the proposed features, however the syntax as described in the #Conclusion is intended to represent the preferred usage.

In the C++ broker there exists a feature wherby plugins, uniquely identified by a schema package and a class name, can have ACLs applied to them. This will also become available in the Java broker, and would be permissioned using the OBJECT object type. This allows objects that are external to the broker to be controlled. For the Java broker it is intended that the main class for a plugin would check with the security manager using the Java package and class names as properties, as below.

ACL ALLOW kittens ACCESS OBJECT package="com.example.plugin" class="Example"

When management functions are being permissioned, a symbolic name for a logical grouping of related methods, properties, attributes and operations is used to identify what is being controlled. This is identified using the component property in the examples above. These groupings will map onto JMX managed objects or MBeans, QMF management schemas, or some other form of mangement object. It is intended that a particular broker implementation handles these mappings internally and ignores mappings that do not exist, such as logging management on the C++ broker currently. It is also possible to offer finer grained control by specifying the name property for the ACL entry, thus restricting the scope to a single method or property. It may also be possible to specify other properties that have meaning for a paricular broker implementation, thus maintaining backward compatibility. The list of possible property names should be fixed as part of the definition of the ACL file format.

Andrew D Kennedy, andrew.international@gmail.com, 2010-05-20

  • No labels