This week I worked with David Booschaert. David proposed a patch for Karaf 3.0.0 to add the notion of groups and use ACL for JMX.
He posted a blog entry about that: http://coderthoughts.blogspot.fr/2013/10/jmx-role-based-access-control-for-karaf.html.
David’s blog is very detailed, mostly in term of implementation, the usage of the interceptor, etc. This blog is more about the pure end-user usage: how to configure group, JMX ACL, etc.
JAAS users, groups, and roles
Karaf uses JAAS for user authentication and authorisation. By default, it uses the PropertiesLoginModule, which use the etc/users.properties file to store the users.
The etc/users.properties file has the following format:
that means we have an user karaf, with password karaf, and admin for role.
Actually, the roles are not really used in Karaf: for instance, when you use ssh or JMX, Karaf checks the principal and credentials (basically the username and password) but it doesn’t really use the roles. All users have exactly the same permissions (basically all permissions): they can execute any shell commands, access to any MBeans and call any operation on these MBeans.
More over, the roles are “only” assigned by users. So, it means that we had to define the same roles list for two different users: it was the only way to assign the same roles list to different users.
So, in addition of users and roles, we introduced JAAS groups.
An user can be a member of a group or have roles assigned directly (as previously).
A groups has typically one or more roles assigned. An user that is part of that group will get these roles associated too.
Finally, an user has the union of the roles associated with his groups, togeher with his own roles.
Basically, the etc/users.properties file doesn’t change in terms of format. We just introduced a prefix to identify a group: _g_. An “user” with the _g_: prefix is actually a group.
So a group is defined as an user, and it’s possible to use a group in the list of roles of an user:
karaf = karaf,_g_:admingroup
manager = manager,_g_:managergroup
other = other,_g_:managergroup,otherrole
_g_\:admingroup = admin,viewer,manager
_g_\:managergroup = viewer,manager
We updated the jaas:* shell commands to be able to manage groups, roles, and users:
karaf@root> jaas:realm-manage --realm karaf
karaf@root> jaas:group-add managergroup
karaf@root> jaas:group-add --help
karaf@root> jaas:user-add joe joe
karaf@root> jaas:group-add joe managergroup
karaf@root> jaas:group-role-add managergroup manager
karaf@root> jaas:group-role-add managergroup viewer
karaf@root> jaas:realm-manage --realm karaf
User Name | Group | Role
karaf | admingroup | admin
karaf | admingroup | manager
karaf | admingroup | viewer
joe | managergroup | manager
joe | managergroup | viewer
Thanks to the groups, it’s possible to factorise the roles, and easily share different roles between the different users.
Define JMX ACLs based on roles
As explained before, the roles were not really used by Karaf. Especially, on the JMX layer, for instance, using jconsole with karaf user, you were able to see all MBeans and perform all operations.
So, we introduced the support of ACL (AccessLists) on JMX.
Now, whenever a JMX operation is invoked, the roles of the current user are checked against the required roles for this operation.
The ACL are defined using configuration files in the Karaf etc folder.
The ACL configuration file is prefixed with jmx.acl and completed with the MBean ObjectName that it applies to.
For example, to define the ACL on the MBean foo.bar:type=Test, you will create a configuration file named etc/jmx.acl.foo.bar.Test.cfg.
It’s possible to define more generic configuration file: on the domain (using jmx.acl.foo.bar.cfg) applied to all MBeans in this domain , or the most generic (jmx.acl.cfg) applied to all MBeans.
A very simple configuration file looks like:
# operation = roles
test = admin
getVal = manager,viewer
The configuration file supports different syntax to provide fine-grained operation ACL:
Specific match for the invocation, including arguments value:
test(int)["17"] = role1
It means that only users with role1 assigned will be able to invoke the test operation with 17 as argument value.
Regex match for the invocation:
test(int)[/[0-9]/] = role2
It means that only users with role2 assigned will be able to invoke the test operation with argument between 0 and 9.
Signature match for the invocation:
test(int) = role3
It means that only users with role3 assigned will be able to invoke test operation.
Method name match for the invocation:
test = role4
It means that only the users with role4 assigned will be able to invoke any test operations (whatever the list of arguments is).
A method name wildcard match:
te* = role5
It means that only the users with role5 assigned will be able to invoke any operations matching te* expression.
Karaf looks for required roles using the following process:
- The most specific configuration file is tried first (etc/jmx.acl.foo.bar.Test.cfg).
- If no matching definition is found in the specific configuration file, a more generic configuration file is inspected. In our case, Karaf will use etc/jmx.acl.foo.bar.cfg.
- If no matching definition is found in the domain specific configuration file, the most generic configuration file is inspected, etc/jmx.acl.cfg.
The ACLs work for any kind of MBeans including the one from the JVM itself. For instance, it’s possible to create etc/jmx.acl.java.lang.Memory.cfg configuration file containing:
gc = manager
It means that only the users with manager role assigned will be able to invoke the gc operation of the JVM Memory MBean.
It’s also possible to define more advanced configuration. For instance, we want that bundles with ID between 0 and 49 can be stopped only by an admin, the other bundles can be stopped by a manager. To do so, we create etc/jmx.acl.org.apache.karaf.bundle.cfg configuration file containing:
stop(java.lang.String)[/([1-4])?[0-9]/] = admin
stop = manager
etc/jmx.acl.cfg configuration file is a global configuration for the invocations of any MBean that doesn’t have a more specific ACL.
By default, we define this configuration:
list* = viewer
get* = viewer
is* = viewer
set* = admin
* = admin
We introduced a new MBean: org.apache.karaf:type=security,area=jmx.
The purpose of this MBean is to check whether the current user can access a certain MBean or invoke a specific operation on it.
This MBean can be used by management clients to decide whether to show certain MBeans or operations to the end user.
What’s next ?
Now, David and I are working on ACL/RBAC for:
- shell commands: as we have ACL for MBeans, it makes sense to apply the same for shell commands.
- OSGi services: the same can be applied to any OSGi service.
I would like to thank David for this great job. It’s a great addition to Karaf and a new very strong reason to promote Karaf 3 😉