DRAFT

ACL Implementation

Use Cases

  1. Allow access to broker functions to be controlled by an ACL, with the checks being carried out independantly of the mechanism used to access the broker. This would mean that a single CREATE QUEUE permission would apply whether the queue was created when a user logged in and used it, or if that user connected to the broker via JMX or QMF and used the management operations to create the queue.
  2. Permissions must be definable at a virtualhost level, with fallback to global permissions. This allows access to be granted for operations only on a certain host, while global operations such as broker administration can be defined at the global level. It also allows default behaviour to be specified globally and then overridden on a per-host basis.
  3. The ACL mechanism controls access to operations on particular objects for all users, if at least one user has a rule controlling access to that operation on that type of object. This means that all users requiring access to a particular operation must be configured. The default behaviour will be to deny access.
  4. It should be possible for the addition of one access control rule to trigger the addition of other rules, to simplify creation of rulesets.
  5. The behaviour of the access control mechanism should be configurable.

Plugin interaction

The plugins can return four different values - ALLOWED, DENIED, ABSTAIN and DEFER. Since we can have two plugins of the same type looking at a particular access request, one for the virtual host and the other for global, the reults ineract as follows:

Host

Global

Result

ALLOWED

any

ALLOWED

DENIED

any

DENIED

ABSTAIN

ALLOWED

ALLOWED

ABSTAIN

DENIED

DENIED

ABSTAIN

ABSTAIN

ABSTAIN

ABSTAIN

DEFER

global

ABSTAIN

none

ABSTAIN

DEFER

ALLOWED

ALLOWED

DEFER

DENIED

DENIED

DEFER

ABSTAIN

host

DEFER

DEFER

global

DEFER

none

host

The host and global entries in the Result column indicate that the default answer for that plugin should be returned.

ACL File

The access control file consists of a series of rules, describing the permissions granted to users or groups for operations on object types, with specific properties. these are all restricted to certain values, as illustrated by the following lists of tokens:

Permission

ALLOW, ALLOW_LOG, DENY, DENY_LOG

Operation

ALL, CONSUME, PUBLISH, CREATE, ACCESS, CONNECT, BIND, UNBIND, DELETE, PURGE, UPDATE, (ADMIN ?)

ObjectType

ALL, VIRTUALHOST, QUEUE, TOPIC, EXCHANGE, BROKER, LINK, ROUTE, METHOD, (USER, LOG, CONFIG ?)

ObjectProperty

ROUTING_KEY, NAME, QUEUE_NAME, OWNER, TYPE, ALTERNATE, INTERNAL, NO_WAIT, NO_LOCAL, NO_ACK, PASSIVE, DURABLE, EXCLUSIVE, TEMPORARY, AUTO_DELETE

The ObjectProperties are keys that are listed as key = value pairs after an Operation/ObjectType combination. They must be in this format; a lone string is not accepted here. This is to make the ACL entries less ambiguous.

Allowed Combinations

The object types and operations are related, with only certain combinations allowed. The table below lists allowed combinations with y and possible combinations as ?. The rows contain ObjectTypes and the columns Operations.

 

CONSUME

PUBLISH

CREATE

ACCESS

BIND

UNBIND

DELETE

PURGE

UPDATE

ADMIN

VIRTUALHOST

 

 

 

y

 

 

 

 

 

?

QUEUE

y

y

y

 

 

 

y

y

 

 

TOPIC

y

y

y

 

 

 

y

 

 

 

EXCHANGE

 

 

y

 

y

y

y

 

 

 

BROKER

 

 

 

y

 

 

 

 

 

?

LINK

 

 

 

 

 

 

 

 

 

 

ROUTE

 

 

 

 

 

 

 

 

 

 

METHOD

 

 

 

?

 

 

 

 

?

?

USER

 

 

 

 

 

 

 

 

?

?

LOG

 

 

 

 

 

 

 

 

 

?

CONFIG

 

 

 

 

 

 

 

 

 

?

To access JMX/QMF attributes there are still some questions. The ADMIN operation could be used, with a set of object types describing the different broker-wide objects that can be manged, sich as LOG, USER and CONFIG. Alternatively, the METHOD object is currently used by the C++ broker ACL files. The type of operation is usually determined by the name of the method, with get*, is* and query* being read (as well as invoked JMX methods that have an impact of INFO) and set* being write, any other method would be usually an operation with side effects. These operations, if they are creating queues etc. can be permissioned using those ACLs. It is only actions that can only be performed through the admin interfaces that need special handling. The fact that the type of operation is defined by the method name makes these ACLs different from the others - it makes no sense to have both UPDATE and ACCESS, eg. adding UPDATE permission for a read method, or ACCESS permission for a write method or other operation.

For instance, to permission access using the METHOD object, I suggest

ACL ALLOW admin ACCESS METHOD name=get*
ACL ALLOW adk ACCESS METHOD name=*
ACL ALLOW other ACCESS METHOD name=createQueue

I am, however, more in favour of abandoning the METHOD based mechanism, in favour of enumerating the objects that can be accessed via the management interfaces, such as QUEUE, USER etc. and adding ACCESS and UPDATE, possibly ADMIN/MANAGE operations to them where this is useful or possible.

ACL Configuration

These are true/false properties that can be specified to confgure the ACL mechanism further, and would be added to the start of an ACL file.

Syntax

  1. Whitespace is considered to be any ASCII byte with a value below 0x20, and is ignored when it occurs between tokens.
  2. Continuations using the '\' character (ASCII 0x5c) are allowed anywhere on a line, and can consist of a blank line with a continuation character as the lat non-whitespace token
  3. Comments are line-style comments, and any text after an un-quoted '#' (ASCII 0x23) are ignored, including continuations. The '#' charater may appear in a quoted string.
  4. Quoted strings consist of any ASCII inside matching pairs of ''' or '"' (ASCII 0x27 and 0x22) characters, including any otherwise special characters.
  5. Tokens are NOT case sensitive, but quoted strings ARE.
  6. The '=' (ASCII 0x3d) character is special, and is used to indicate property value assignment.
  7. Wildcards are specified using the '*' (ASCII 0x2a) character in a property value string, which may be quoted.

The declarations are as follows, using some kind of grammar, with + and * having the usual regular expression meanings, parenthesis denote grouping and brackets denote optional elements.

CONFIG ( <config-property> '=' <TRUE | FALSE> ) +
GROUP <group-name> ( <username | group-name> ) +
[ <number> ] ACL <permission> <username | group-name | ALL> <operation> [ <object-type> ( <property-name> '=' <property-value> ) * ]

This allows a rather looser and more readable style for ACL files, while still retaining the ability to read the stricter files accepted by the C++ broker. Bear in mind that the group declarations are to be deprecated, in favour of an external directory service, using a plugin mechanism.

The initial <number> is used to allow rulesets to be created which allow indicidual rules to be enabled and disabled using an admin interface, and an ACL file using numbered lines would be restricted to having increasing numbers per rule, although gaps would be allowed to enable rules to be inserted later, again using an admin interface. This administrative interface would also allow saving of a modified ruleset and re-loading.

Examples

    Allow "adk@iterator.co.uk" Create Queue \
        Owner="adk@iterator.co.uk" Routingkey = "chocolate biscuits" \
        QueueName="kitten.*"
# allow adk to create queues
Allow "adk@iterator.co.uk" Create Queue \
    Owner = "adk@iterator.co.uk" \
    Routingkey = "chocolate biscuits" \
    QueueName=kitten
# allow adk access to this virtual host
110 ALLOW "adk@iterator" ACCESS VIRTUALHOST

# allow creating temporary queues and queues with names matching adk.*
210 ALLOW-LOG \
        "adk@iterator" BIND EXCHANGE \
        routingKey="adk.*" \
        name="amq.direct" # allow adk.* queue bind to amq.direct
220 \
        ALLOW-LOG "adk@iterator" BIND EXCHANGE \
        routingKey="tmp.*" name="amq.direct"
230 ALLOW "adk@iterator" CREATE QUEUE name="adk.*" owner="adk@iterator"
240 ALLOW "adk@iterator" CREATE QUEUE temporary="true" owner="adk@iterator"

# allow publish and consume of messages on the queues
310 ALLOW "adk@iterator" CONSUME QUEUE name="adk.*"
315 ALLOW "adk@iterator" PUBLISH QUEUE routingkey="adk.export#extra" // foo
320 ALLOW "adk@iterator" PUBLISH QUEUE name="adk.*"

# default deny
910 DENY ALL ALL ALL

== METHOD considered harmful ==

A lot of the object types and operations used in the ACL file are shared
between the Java and C++ brokers and are non-contentious, since they
represent actual objects that exist in AMQP - broker, queue, exchange
and so forth. What appears to be at issue is how to permission extra
funtionality in the broker, such as administration of user accounts or
logging levels The C++ broker's 'METHOD' object is one mechanism, and
results in ACL lines that specify a single method or set of methods that
can be executed, and does not convey whether these are reading, writing
or have other side effects on the broker. An example is shoen below:

ACL ALLOW adk UPDATE METHOD name=getLoggingLevel
ACL ALLOW adk UPDATE METHOD name=setLoggingLevel
ACL ALLOW adk UPDATE METHOD name=reloadLoggingConfig

This seems to be at the wrong level of abstraction. Looking at this
in a general fashion, there are three things we wish to do to objects:
get a property, set a property and execute an operation. These can be
mapped to READ, WRITE, EXECUTE or GET, SET, INVOKE, ACCESS, UPDATE,
ADMIN, and so on as operations. The next step would be to decide what
the object type is that is being manipulated. I would be happy for this
to be one of the existing AMQP objects, including BROKER, since this
follows the existing pattern of permissions. Another point to note is
that existing mechanisms such as JMX already have the conceptual split
into these three types of action.

If we abandon the METHOD object in favour of existing object types, we
still need to be able to permission such items as users and logging, and
I propose these are made part of the broker object, with the possibility
of adding other, vendor-specific extensions too. This would result in ACL
lines as shown below, which would grant permission to view attributes
of the logging subsystem, update those attributes and execute other
administrative actions. Finally, if there is a management schema change
and the names of methods used change, or new methods and attributes are
added, the ACL file does not have to be changed, since the permissions
relate to subsystems or extensions.

ACL ALLOW adk ACCESS BROKER extension=logging
ACL ALLOW adk UPDATE BROKER extension=logging
ACL ALLOW adk ADMIN BROKER extension=logging
or
ACL ALLOW adk ADMIN BROKER subsystem=acl

If we want to create an ACL file format that is usable across AMQP
brokers, then the use of 'extension=<name>' or 'subsystem=<name>' with
a set of pre-defined names, say 'logging', 'users', 'configuration',
and a naming convention to prevent clashes, such as 'x-<vendor>-*'
for vendor specific implementations or just 'x-*' for experimental
extensions/subsystems seems appropriate.