2.2. Role-Based Access Control

Abstract

This section describes the role-based access control (RBAC) feature, which is enabled by default in the JBoss Fuse container. You can immediately start taking advantage of the RBAC feature, simply by adding one of the standard roles (such as Deployer or Administrator) to a user's credentials. For more advanced usage, you have the option of customizing the access control lists, in order to control exactly what each role can do. Finally, you have the option of applying custom ACLs to your own OSGi services.

2.2.1. Overview of Role-Based Access Control

Overview

By default, the JBoss Fuse role-based access control protects access through the Fuse Management Console, JMX connections, and the Karaf command console. To use the default levels of access control, simply add any of the standard roles to your user authentication data (for example, by editing the etc/users.properties file). You also have the option of customizing access control, by editing the relevant Access Control List (ACL) files.

Mechanisms

Role-based access control in JBoss Fuse is based on the following mechanisms:
JMX Guard
The JBoss Fuse container is configured with a JMX guard, which intercepts every incoming JMX invocation and filters the invocation through the configured JMX access control lists. The JMX guard is configured at the JVM level, so it intercepts every JMX invocation, without exception.
OSGi Service Guard
For any OSGi service, it is possible to configure an OSGi service guard. The OSGi service guard is implemented as a proxy object, which interposes itself between the client and the original OSGi service. An OSGi service guard must be explicitly configured for each OSGi service: it is not installed by default (except for the OSGi services that represent Karaf console commands, which are preconfigured for you).
Note
If you change the configuration of RBAC, the changes propagation to Hawtio may take up to 10 minutes due to cache update.

Types of protection

The JBoss Fuse implementation of role-based access control is capable of providing the following types of protection:
Fuse Management Console (Hawtio)
Container access through the Fuse Management Console (Hawtio) is controlled by the JMX ACL files. The REST/HTTP service that provides the Fuse Management Console is implemented using Jolokia technology, which is layered above JMX. Hence, ultimately, all Fuse Management Console invocations pass through JMX and are regulated by JMX ACLs.
JMX
Direct access to the container's JMX port is regulated by the JMX ACLs. Moreover, any additional JMX ports opened by an application running in the container would also be regulated by the JMX ACLs, because the JMX guard is set at the JVM level.
Karaf command console
Access to the Karaf command console is regulated by the command console ACL files. Access control is applied no matter how the Karaf console is accessed. Whether accessing the command console through the Fuse Management Console or through the SSH protocol, access control is applied in both cases.
Note
In the special case where you start up the container directly at the command line (for example, using the ./bin/fuse script) and no user authentication is performed, you automatically get the roles specified by the karaf.local.roles property in the etc/system.properties file.
OSGi services
For any OSGi service deployed in the container, you can optionally enable an ACL file, which restricts method invocations to specific roles.

Adding roles to users

In the system of role-based access control, you can give users permissions by adding roles to their user authentication data. For example, the following entry in the etc/users.properties file defines the admin user and grants the Administrator and SuperUser roles.
admin = secretpass,Administrator,SuperUser
You also have the option of defining user groups and then assigning users to a particular user group. For example, you could define and use an admingroup user group as follows:
admin = secretpass, _g_:admingroup

_g_\:admingroup = Administrator, SuperUser
Note
User groups are not supported by every type of JAAS login module.

Standard roles

Table 2.2, “Standard Roles for Access Control” lists and describes the standard roles that are used throughout the JMX ACLs and the command console ACLs.

Table 2.2. Standard Roles for Access Control

RolesDescription
Monitor, Operator, MaintainerGrants read-only access to the container.
Deployer, AuditorGrants read-write access at the appropriate level for ordinary users, who want to deploy and run applications. But blocks access to sensitive container configuration settings.
Administrator, SuperUserGrants unrestricted access to the container.

ACL files

The standard set of ACL files are located under the etc/auth/ directory of the JBoss Fuse installation, as follows:
etc/auth/jmx.acl[.*].cfg
JMX ACL files.
etc/auth/org.apache.karaf.command.acl.*.cfg
Command console ACL files.

Customizing role-based access control

A complete set of JMX ACL files and command console ACL files are provided by default. You are free to customize these ACLs as required to suit the requirements of your system.
You can create custom roles by editing the ACL files that are located under the etc/auth/ directory of the JBoss Fuse installation. For more information see Customizing the JMX ACLs and Customizing the Command Console ACLs

Customizing ACLs in a fabric environment

In a standalone enviroment, you can assign the custom roles by editing the ACL files. This process does not work in a fabric enviroment as the ACL files in /etc/auth are over-written by the content stored in profiles. Hence, to assign custom roles in a fabric environment, you can add ACL assignments to the acl profile or jboss-fuse-full profile. For example,
fabric:profile-edit --pid org.apache.karaf.command.acl.fabric/container-start="Deployer, Auditor, Administrator, SuperUser, admin, MyCustomRoleForStartingContainer" acls

Additional properties for controlling access

The system.properties file under the etc directory provides the following additional properties for controlling access through the Karaf command console and the Fuse Management Console (Hawtio):
karaf.local.roles
Specifies the roles that apply when a user starts up the container console locally (for example, by running the ./bin/fuse script).
hawtio.roles
Specifies the roles that are allowed to access the container through the Fuse Management Console. This constraint is applied in addition to the access control defined by the JMX ACL files.
karaf.secured.command.compulsory.roles
Specifies the default roles required to invoke a Karaf console command, in case the console command is not configured explicitly by a command ACL file, etc/auth/org.apache.karaf.command.acl.*.cfg. A user must be configured with at least one of the roles from the list in order to invoke the command. The value is specified as a comma-separated list of roles.

2.2.2. Customizing the JMX ACLs

Overview

The JMX ACLs are stored in the OSGi Config Admin Service and are normally accessible as the files, etc/auth/jmx.acl.*.cfg. This section explains how you can customize the JMX ACLs by editing these files yourself.

Architecture

Figure 2.1, “Access Control Mechanism for JMX” shows an overview of the role-based access control mechanism for JMX connections to the JBoss Fuse container.

Figure 2.1. Access Control Mechanism for JMX

Access Control Mechanism for JMX

How it works

JMX access control works by inserting a JMX Guard, which is configured through a JVM-wide MBeanServerBuilder object. The Apache Karaf launching scripts have been modified to include the following setting:
-Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder
JMX access control is now applied as follows:
  1. For every non-local JMX invocation, the JVM-wide MBeanServerBuilder calls into an OSGi bundle that contains the JMX Guard.
  2. The JMX Guard looks up the relevant ACL for the MBean the user is trying to access (where the ACLs are stored in the OSGi Config Admin service).
  3. The ACL returns the list of roles that are allowed to make this particular invocation on the MBean.
  4. The JMX Guard checks the list of roles against the current security subject (the user that is making the JMX invocation), to see whether the current user has any of the required roles.
  5. If no matching role is found, the JMX invocation is blocked and a java.lang.SecurityException is raised.

Location of JMX ACL files

The JMX ACL files are located in the InstallDir/etc/auth directory, where the ACL file names obey the following convention:
etc/auth/jmx.acl[.*].cfg
Technically, the ACLs are mapped to OSGi persistent IDs (PIDs), matching the pattern, jmx.acl[.*]. It just so happens that the standalone container stores OSGi PIDs as files, PID.cfg, under the etc/ directory by default.

Mapping MBeans to ACL file names

The JMX Guard applies access control to every MBean class that is accessed through JMX (including any MBeans you define in your own application code). The ACL file for a specific MBean class is derived from the MBean's Object Name, by prefixing it with jmx.acl. For example, given the MBean whose Object Name is given by org.apache.activemq:type=Broker, the corresponding PID would be:
jmx.acl.org.apache.activemq.Broker
In the case of a standalone container, the OSGi Config Admin service stores this PID data in the following file:
etc/auth/jmx.acl.org.apache.activemq.Broker.cfg

ACL file format

Each line of a JMX ACL file is an entry in the following format:
Pattern = Role1[,Role2][,Role3]...
Where Pattern is a pattern that matches a method invocation on an MBean, and the right-hand side of the equals sign is a comma-separated list of roles that give a user permission to make that invocation. In the simplest cases, the Pattern is simply a method name. For example, as in the following settings for the org.apache.activemq.Broker MBean (from the jmx.acl.org.apache.activemq.Broker.cfg file):
addConnector = Deployer, Auditor, Administrator, SuperUser
removeConnector = Deployer, Auditor, Administrator, SuperUser
enableStatistics = Deployer, Auditor, Administrator, SuperUser
addNetworkConnector = Deployer, Auditor, Administrator, SuperUser
It is also possible to use the wildcard character, *, to match multiple method names. For example, the following entry gives permission to invoke all method names starting with set:
set* = Deployer, Auditor, Administrator, SuperUser
But the ACL syntax is also capable of defining much more fine-grained control of method invocations. You can define patterns to match methods invoked with specific arguments or even arguments that match a regular expression. For example, the ACL for the org.apache.karaf.config MBean package exploits this capability to prevent ordinary users from modifying sensitive configuration settings. The create method from this package is restricted, as follows:
create(java.lang.String)[/jmx[.]acl.*/] = Administrator, SuperUser
create(java.lang.String)[/org[.]apache[.]karaf[.]command[.]acl.+/] = Administrator, SuperUser
create(java.lang.String)[/org[.]apache[.]karaf[.]service[.]acl.+/] = Administrator, SuperUser
create(java.lang.String) = Deployer, Auditor, Administrator, SuperUser
In this case, the Deployer and Auditor roles generally have permission to invoke the create method, but only the Administrator and SuperUser roles have permission to invoke create with a PID argument matching jmx.acl.*, org.apache.karaf.command.acl.*, or org.apache.karaf.service.*.
For complete details of the ACL file format, please see the comments in the etc/auth/jmx.acl.cfg file.

ACL file hierarchy

Because it is often impractical to provide an ACL file for every single MBean, you have the option of specifying an ACL file at the level of a Java package, which provides default settings for all of the MBeans in that package. For example, the org.apache.activemq.Broker MBean could be affected by ACL settings at any of the following PID levels:
jmx.acl.org.apache.activemq.Broker
jmx.acl.org.apache.activemq
jmx.acl.org.apache
jmx.acl.org
jmx.acl
Where the most specific PID (top of the list) takes precedence over the least specific PID (bottom of the list).

Root ACL definitions

The root ACL file, jmx.acl.cfg, is a special case, because it supplies the default ACL settings for all MBeans. The root ACL has the following settings by default:
list* = viewer, Monitor, Operator, Maintainer,Deployer, Auditor, Administrator, SuperUser
get* = viewer, Monitor, Operator, Maintainer,Deployer, Auditor, Administrator, SuperUser
is* = viewer, Monitor, Operator, Maintainer,Deployer, Auditor, Administrator, SuperUser
set* = admin, Administrator, SuperUser
* = admin, Administrator, SuperUser
This implies that the typical read method patterns (list*, get*, is*) are accessible to all standard roles, but the typical write method patterns and other methods (set* and *) are accessible only to the administrator roles, admin, Administrator, SuperUser.

Package ACL definitions

Many of the standard JMX ACL files provided in etc/auth/jmx.acl[.*].cfg apply to MBean packages. For example, the ACL for the org.apache.camel.endpoints MBean package is defined with the following permissions:
is* = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
get* = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
set* = Deployer, Auditor, Administrator, SuperUser

ACL for custom MBeans

If you define custom MBeans in your own application, these custom MBeans are automatically integrated with the ACL mechanism and protected by the JMX Guard when you deploy them into the container. By default, however, your MBeans are typically protected only by the default root ACL file, jmx.acl.cfg. If you want to define a more fine-grained ACL for your MBean, create a new ACL file under etc/auth, using the standard JMX ACL file naming convention.
For example, if your custom MBean class has the JMX Object Name, org.example:type=MyMBean, create a new ACL file under the etc/auth directory called:
jmx.acl.org.example.MyMBean.cfg

Dynamic configuration at run time

Because the OSGi Config Admin service is dynamic, you can change ACL settings while the system is running, and even while a particular user is logged on. Hence, if you discover a security breach while the system is running, you can immediately restrict access to certain parts of the system by editing the relevant ACL file, without having to restart the container.

2.2.3. Customizing the Command Console ACLs

Overview

The command console ACLs are stored in the OSGi Config Admin Service and are normally accessible as the files, etc/auth/org.apache.karaf.command.acl.*.cfg. This section explains how you can customize the command console ACLs by editing these files yourself.

Architecture

Figure 2.2, “Access Control Mechanism for OSGi Services” shows an overview of the role-based access control mechanism for OSGi services in the JBoss Fuse container.

Figure 2.2. Access Control Mechanism for OSGi Services

Access Control Mechanism for OSGi Services

How it works

The mechanism for command console access control is, in fact, based on the generic access control mechanism for OSGi services. It so happens that console commands are implemented and exposed as OSGi services. The Karaf console itself discovers the available commands through the OSGi service registry and accesses the commands as OSGi services. Hence, the access control mechanism for OSGi services can be used to control access to console commands.
The mechanism for securing OSGi services is based on OSGi Service Registry Hooks. This is an advanced OSGi feature that makes it possible to hide OSGi services from certain consumers and to replace an OSGi service with a proxy service.
When a service guard is in place for a particular OSGi service, a client invocation on the OSGi service proceeds as follows:
  1. The invocation does not go directly to the requested OSGi service. Instead, the request is routed to a replacement proxy service, which has the same service properties as the original service (and some extra ones).
  2. The service guard looks up the relevant ACL for the target OSGi service (where the ACLs are stored in the OSGi Config Admin service).
  3. The ACL returns the list of roles that are allowed to make this particular method invocation on the service.
  4. If no ACL is found for this command, the service guard defaults to the list of roles specified in the karaf.secured.command.compulsory.roles property in the etc/system.properties file.
  5. The service guard checks the list of roles against the current security subject (the user that is making the method invocation), to see whether the current user has any of the required roles.
  6. If no matching role is found, the method invocation is blocked and a java.lang.SecurityException is raised.
  7. Alternatively, if a matching role is found, the method invocation is delegated to the original OSGi service.

Configuring default security roles

For any commands that do not have a corresponding ACL file, you specify a default list of security roles by setting the karaf.secured.command.compulsory.roles property in the etc/system.properties file (specified as a comma-separated list of roles).

Location of command console ACL files

The command console ACL files are located in the InstallDir/etc/auth directory, with the prefix, org.apache.karaf.command.acl.

Mapping command scopes to ACL file names

The command console ACL file names obey the following convention:
etc/auth/org.apache.karaf.command.acl.CommandScope.cfg
Where the CommandScope corresponds to the prefix for a particular group of Karaf console commands. For example, the features:install and features:uninstall commands belong to the features command scope, which has the corresponding ACL file, org.apache.karaf.command.acl.features.cfg.

ACL file format

Each line of a command console ACL file is an entry in the following format:
Pattern = Role1[,Role2][,Role3]...
Where Pattern is a pattern that matches a Karaf console command from the current command scope, and the right-hand side of the equals sign is a comma-separated list of roles that give a user permission to make that invocation. In the simplest cases, the Pattern is simply an unscoped command name. For example, the org.apache.karaf.command.acl.features.cfg ACL file includes the following rules for the features commands:
list = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
listRepositories = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
listUrl = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
info = Monitor, Operator, Maintainer, Deployer, Auditor, Administrator, SuperUser
install = Administrator,SuperUser
uninstall = Administrator,SuperUser
Important
If no match is found for a specific command name, it is assumed that no role is required for this command and it can be invoked by any user.
You can also define patterns to match commands invoked with specific arguments or even arguments that match a regular expression. For example, the org.apache.karaf.command.acl.osgi.cfg ACL file exploits this capability to prevent ordinary users from invoking the osgi:start and osgi:stop commands with the -f (force) flag (which must be specified to manage system bundles). This restriction is coded as follows in the ACL file:
start[/.*[-][f].*/] = Administrator, SuperUser
start = Deployer, Auditor, Administrator, SuperUser
stop[/.*[-][f].*/] = Administrator, SuperUser
stop = Deployer, Auditor, Administrator, SuperUser
In this case, the Deployer and Auditor roles generally have permission to invoke the osgi:start and osgi:stop commands, but only the Administrator and SuperUser roles have permission to invoke these commands with the force option, -f.
For complete details of the ACL file format, please see the comments in the etc/auth/org.apache.karaf.command.acl.osgi.cfg file.

Dynamic configuration at run time

The command console ACL settings are fully dynamic, which means you can change the ACL settings while the system is running and the changes will take effect within a few seconds, even for users that are already logged on.

2.2.4. Defining ACLs for OSGi Services

Overview

It is possible to define a custom ACL for any OSGi service (whether system level or application level). By default, OSGi services do not have access control enabled (with the exception of the OSGi services that expose Karaf console commands, which are pre-configured with command console ACL files). This section explains how to define a custom ACL for an OSGi service and how to invoke methods on that service using a specified role.

ACL file format

An OSGi service ACL file has one special entry, which identifies the OSGi service to which this ACL applies, as follows:
service.guard = (objectClass=InterfaceName)
Where the value of service.guard is an LDAP search filter that is applied to the registry of OSGi service properties in order to pick out the matching OSGi service. The simplest type of filter, (objectClass=InterfaceName), picks out an OSGi service with the specified Java interface name, InterfaceName.
The remaining entries in the ACL file are of the following form:
Pattern = Role1[,Role2][,Role3]...
Where Pattern is a pattern that matches a service method, and the right-hand side of the equals sign is a comma-separated list of roles that give a user permission to make that invocation. The syntax of these entries is essentially the same as the entries in a JMX ACL file—see the section called “ACL file format”.

How to define an ACL for a custom OSGi service

To define an ACL for a custom OSGi service, perform the following steps:
  1. It is customary to define an OSGi service using a Java interface (you could use a regular Java class, but this is not recommended). For example, consider the Java interface, MyService, which we intend to expose as an OSGi service:
    package org.example;
    
    public interface MyService {
      void doit(String s);
    }
  2. To expose the Java interface as an OSGi service, you would typically add a service element to an OSGi Blueprint XML file (where the Blueprint XML file is typically stored under the src/main/resources/OSGI-INF/blueprint directory in a Maven project). For example, assuming that MyServiceImpl is the class that implements the MyService interface, you could expose the MyService OSGi service as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                default-activation="lazy">
      
      <bean id="myserviceimpl" class="org.example.MyServiceImpl"/>
      
      <service id="myservice" ref="myserviceimpl" interface="org.example.MyService"/>
      
    </blueprint>
  3. To define an ACL for the the OSGi service, you must create an OSGi Config Admin PID with the prefix, org.apache.karaf.service.acl.
    For example, in the case of a standalone container (where the OSGi Config Admin PIDs are stored as .cfg files under the etc/auth/ directory), you can create the following ACL file for the MyService OSGi service:
    etc/auth/org.apache.karaf.service.acl.myservice.cfg
    Note
    It does not matter exactly how you name this file, as long as it starts with the required prefix, org.apache.karaf.service.acl. The corresponding OSGi service for this ACL file is actually specified by a property setting in this file (as you will see in the next step).
  4. Specify the contents of the ACL file in a format like the following:
    service.guard = (objectClass=InterfaceName)
    Pattern = Role1[,Role2][,Role3]...
    The service.guard setting specifies the InterfaceName of the OSGi service (using the syntax of an LDAP search filter, which is applied to the OSGi service properties). The other entries in the ACL file consist of a method Pattern, which associates a matching method to the specified roles. For example, you could define a simple ACL for the MyService OSGi service with the following settings in the org.apache.karaf.service.acl.myservice.cfg file:
    service.guard = (objectClass=org.example.MyService)
    doit = Deployer, Auditor, Administrator, SuperUser
  5. Finally, in order to enable the ACL for this OSGi service, you must edit the karaf.secured.services property in the etc/system.properties file. The value of the karaf.secured.services property has the syntax of an LDAP search filter (which gets applied to the OSGi service properties). In general, to enable ACLs for an OSGi service, ServiceInterface, you must modify this property as follows:
    karaf.secured.services=(|(objectClass=ServiceInterface)(...ExistingPropValue...))
    For example, to enable the MyService OSGi service:
    karaf.secured.services=(|(objectClass=org.example.MyService)(&(osgi.command.scope=*)(osgi.command.function=*)))
    Caution
    The initial value of the karaf.secured.services property has the settings to enable the command console ACLs. If you delete or corrupt these entries, the command console ACLs might stop working.

How to invoke an OSGi service secured with RBAC

If you are writing Java code to invoke methods an a custom OSGi service (that is, implementing a client of the OSGi service), you must use the Java security API to specify the role you are using to invoke the service. For example, to invoke the MyService OSGi service using the Deployer role, you could use code like the following:
// Java
import javax.security.auth.Subject;
import org.apache.karaf.jaas.boot.principal.RolePrincipal;
// ... 
Subject s = new Subject();
s.getPrincipals().add(new RolePrincipal("Deployer"));
Subject.doAs(s, new PrivilegedAction() {
  public Object run() {
    svc.doit("foo"); // invoke the service
  }
}
Note
This example uses the Karaf role type, org.apache.karaf.jaas.boot.principal.RolePrincipal. If necessary, you could use your own custom role class instead, but in that case you would have to specify your roles using the syntax className:roleName in the OSGi service's ACL file.

How to discover the roles required by an OSGi service

When you are writing code against an OSGi service secured by an ACL, it can sometimes be useful to check what roles are allowed to invoke the service. For this purpose, the proxy service exports an additional OSGi property, org.apache.karaf.service.guard.roles. The value of this property is a java.util.Collection object, which contains a list of all the roles that could possibly invoke a method on that service.