Chapter 10. Security
This chapter covers the various security options available to administrators, and how they are configured. Administrators can use the information provided in this chapter to tailor the functions of the Red Hat JBoss AMQ security subsystems to their needs.
10.1. Securing Network Connections
There are two basic use cases for transport layer security (TLS):
- Server-side (or one-way); where only the server presents a certificate. This is the most common use case.
- Client-side (or two-way); where both the server and the client present certificates. This is sometimes called mutual authentication.
10.1.1. Configuring Server-Side Certificates
One-way TLS is configured in the URL of the relevant acceptor
in broker.xml
. Here is a very basic acceptor
configuration which does not use TLS:
<acceptor name="artemis">tcp://0.0.0.0:61616</acceptor>
Here is that same acceptor
configured to use one-way TLS:
<acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!</acceptor>
This acceptor
uses three additional parameters - sslEnabled
, keyStorePath
, and keyStorePassword
. These, at least, are required to enable one-way TLS.
10.1.2. Configuring Client-Side Certificates
Two-way TLS uses the same sslEnabled
, keyStorePath
, and keyStorePassword
properties as one-way TLS, but it adds needClientAuth
to tell the client it should present a certificate of its own. For example:
<acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!;needClientAuth=true</acceptor>
This configuration assumes that the client’s certificate is signed by a trusted provider. If the client’s certificate is not signed by a trusted provider (it is self-signed, for example) then the server needs to import the client’s certificate into a trust-store and configure the acceptor with trustStorePath
and trustStorePassword
. For example:
<acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!;needClientAuth=true;trustStorePath=../etc/client.truststore;trustStorePassword=5678!</acceptor>
AMQ Broker supports multiple protocols, and each protocol and platform has different ways to specify TLS parameters. However, in the case of a client using the Core protocol (a bridge) the TLS parameters are configured on the connector URL much like on the broker’s acceptor.
TLS Configuration Details
Below are configuration details to be aware of:
Option | Note |
---|---|
|
Must be |
|
When used on an
When used on a |
|
When used on an
When used on a |
|
When used on an
When used on a |
|
When used on an
When used on a |
|
Whether used on an |
|
Whether used on an |
|
This property is only for an |
10.1.3. Adding Certificate-based Authentication
The JAAS certificate authentication login module requires TLS to be in use and clients must be configured with their own certificates. In this scenario, authentication is actually performed during the TLS handshake, not directly by the JAAS certificate authentication plug-in.
The role of the plug-in is as follows:
- To further constrain the set of acceptable users, because only the user Distinguished Names (DNs) explicitly listed in the relevant properties file are eligible to be authenticated.
- To associate a list of groups with the received user identity, facilitating integration with authorization.
- To require the presence of an incoming certificate (by default, the TLS layer is configured to treat the presence of a client certificate as optional).
The JAAS certificate login module stores a collection of certificate DNs in a pair of flat files. The files associate a username and a list of group IDs with each Distinguished Name.
The certificate login module is implemented by the org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
class.
Prerequisites
-
Certificate login configured in
login.config
file. -
A valid
user.properties
file. -
A valid
roles.properties
file. - The Subject DNs from the user certificate(s)
Procedure
Obtain the Subject DNs from user certificates
Export the certificate from the keystore file into a temporary file. Substitute your required values into the following command:
keytool -export -file __FILENAME__ -alias broker-localhost -keystore broker.ks -storepass __PASSWORD__
Print the contents of the exported certificate:
keytool -printcert -file __FILENAME__
The output is similar to that shown below:
Owner: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown 1 Issuer: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown Serial number: 4537c82e Valid from: Thu Oct 19 19:47:10 BST 2006 until: Wed Jan 17 18:47:10 GMT 2007 Certificate fingerprints: MD5: 3F:6C:0C:89:A8:80:29:CC:F5:2D:DA:5C:D7:3F:AB:37 SHA1: F0:79:0D:04:38:5A:46:CE:86:E1:8A:20:1F:7B:AB:3A:46:E4:34:5C
- 1
- The subject DN. The format used to enter the subject DN depends on your platform. The string above could also be represented as;
Owner: `CN=localhost,\ OU=broker,\ O=Unknown,\ L=Unknown,\ ST=Unknown,\ C=Unknown`
Configuring certificate-based authentication
-
Open the
login.config
file and reference the user and roles properties files. Open the files declared in the previous step and supply the required information:
Users and their corresponding DNs should be listed in the
users.properties
file. The available roles and the users who hold those roles are defined in theroles.properties
file.Examples of the syntax of these files is shown below.
Ensure your security domain alias (in this instance, activemq) is referenced in
bootstrap.xml
as shown below:<jaas-security domain="activemq"/>
-
Open the
Example Configuration
The following example shows how to configure certificate login module in the login.config
file:
Example 10.1. login.conf
activemq { org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule 1 debug=true 2 org.apache.activemq.jaas.textfiledn.user="users.properties" 3 org.apache.activemq.jaas.textfiledn.role="roles.properties"; 4 };
- 1
- Configure the JAAS realm. This example uses a single
org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
- 2
- Toggle debugging on (
true
) or off (false
). Default isfalse
. - 3
- Define the file used to store user data (relative to the directory containing the
login.config
file). - 4
- Define the file used to store role data (relative to the directory containing the
login.config
file).
The users.properties
file consists of a list of properties with the user=StringifiedSubjectDN
(where the string encoding is specified by RFC 2253):
Example 10.2. users.properties
system=CN=system,O=Progress,C=US 1
user=CN=humble user,O=Progress,C=US
guest=CN=anon,O=Progress,C=DE
- 1
- The user named
system
is mapped to theCN=system,O=Progress,C=US
subject DN.
The roles.properties
file follows the pattern of role=user
where user
can be either a single user or a comma-separated list of users:
Example 10.3. roles.properties
admins=system
users=system,user 1
guests=guest
- 1
- Multiple users can be included as a comma-separated entry.
10.1.4. Using Multiple Login Modules
It is possible to combine login modules to accommodate more complex use cases. The most common reason to combine login modules is to support authentication for both anonymous users and users who submit credentials.
Prerequisites
The prerequisites for different authentication combinations differ based on the methods being implemented. Prerequisites for the most common multiple login scenario are:
-
A valid
users.properties
file -
A valid
roles.properties
file -
A
login.config
file configured for anonymous access
Procedure
-
Edit the
login.config
file to add entries for the desired authentication modules. - Set the parameters in each module entry as required for your environment.
Ensure your security domain alias (in this instance, activemq) is referenced in
bootstrap.xml
as shown below:Example 10.4.
bootstrap.xml
<jaas-security domain="activemq"/>
Example Configuration
The following examples illustrate the cascading nature of multiple login configurations:
Example 10.5. login.conf
activemq { org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient 1 debug=true org.apache.activemq.jaas.properties.user="users.properties" org.apache.activemq.jaas.properties.role="roles.properties"; org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient 2 debug=true org.apache.activemq.jaas.guest.user="guest" org.apache.activemq.jaas.guest.role="restricted"; };
The following example shows how to configure a JAAS login entry for the use case where only those users with no credentials are logged in as guests. Note that the order of the login modules is reversed and the flag attached to the properties login module is changed to requisite
.
Example 10.6. login.conf
activemq { org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient 1 debug=true credentialsInvalidate=true 2 org.apache.activemq.jaas.guest.user="guest" org.apache.activemq.jaas.guest.role="guests"; org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule requisite 3 debug=true org.apache.activemq.jaas.properties.user="users.properties" org.apache.activemq.jaas.properties.role="roles.properties"; };
10.1.5. Configure Multiple Security Settings for Address Groups and Sub-groups
Below is an example security block from a broker.xml
file. It shows various configuration options that will be explained in this section.
<security-setting match="globalqueues.europe.#"> <permission type="createDurableQueue" roles="admin"/> <permission type="deleteDurableQueue" roles="admin"/> <permission type="createNonDurableQueue" roles="admin, guest, europe-users"/> <permission type="deleteNonDurableQueue" roles="admin, guest, europe-users"/> <permission type="send" roles="admin, europe-users"/> <permission type="consume" roles="admin, europe-users"/> </security-setting>
The ‘#’ character signifies "any sequence of words". Words are delimited by the ‘.’ character. For a full description of the wildcard syntax see AMQ Broker Wildcard Syntax. The above security block applies to any address that starts with the string "globalqueues.europe.":
Only users who have the admin
role can create or delete durable queues bound to an address that starts with the string "globalqueues.europe."
Any users with the roles admin
, guest
, or europe-users
can create or delete temporary queues bound to an address that starts with the string "globalqueues.europe."
Any users with the roles admin
or europe-users
can send messages to these addresses or consume messages from queues bound to an address that starts with the string "globalqueues.europe."
The mapping between a user and what roles they have is handled by the security manager. AMQ Broker ships with a user manager that reads user credentials from a file on disk, and can also plug into JAAS or JBoss Application Server security.
There can be multiple security-setting
elements in each XML file, or none, depending on requirements. When the broker.xml
file contains multiple security-setting elements that can apply to a set of addresses, the most specific match takes precedence.
Let us look at an example of that, here’s another security-setting
block:
<security-setting match="globalqueues.europe.orders.#"> <permission type="send" roles="europe-users"/> <permission type="consume" roles="europe-users"/> </security-setting>
In this security-setting
block the match 'globalqueues.europe.orders.#' is more specific than the previous match 'globalqueues.europe.\#'. So any addresses which match 'globalqueues.europe.orders.\#' will take their security settings only from the latter security-setting block.
Note that settings are not inherited from the former block. All the settings will be taken from the more specific matching block, so for the address 'globalqueues.europe.orders.plastics' the only permissions that exist are send
and consume
for the role europe-users. The permissions createDurableQueue
, deleteDurableQueue
, createNonDurableQueue
, deleteNonDurableQueue
are not inherited from the other security-setting block.
By not inheriting permissions, you can effectively deny permissions in more specific security-setting blocks by simply not specifying them. Otherwise it would not be possible to deny permissions in sub-groups of addresses.
10.1.6. Setting Resource Limits
Sometimes it is helpful to set particular limits on what certain users can do beyond the normal security settings related to authorization and authentication. For example, one can limit how many connections a user can create or how many queues a user can create.
10.1.6.1. Configuring Connection and Queue Limits
Here is an example of the XML used to set resource limits:
<resource-limit-settings> <resource-limit-setting match="myUser"> <max-connections>5</max-connections> <max-queues>3</max-queues> </resource-limit-setting> </resource-limit-settings>
Unlike the match
from address-setting
, this match
does not use any wildcard syntax. It is a simple 1:1 mapping of the limits to a user.
-
max-connections
. Defines how many connections the matched user can make to the broker. The default is-1
, which means there is no limit. -
max-queues
. Defines how many queues the matched user can create. The default is-1
, which means there is no limit.
10.2. Integrating with LDAP
10.2.1. Using LDAP for Authentication
The LDAP login module enables authentication and authorization by checking the incoming credentials against user data stored in a central X.500 directory server. It is implemented by org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule
.
Procedure
Open the
BROKER_INSTANCE_DIR/etc/broker.xml
file and add the following lines:<security-settings> <security-setting match="#"> <permission type="createDurableQueue" roles="user"/> <permission type="deleteDurableQueue" roles="user"/> <permission type="createNonDurableQueue" roles="user"/> <permission type="deleteNonDurableQueue" roles="user"/> <permission type="send" roles="user"/> <permission type="consume" roles="user"/> </security-setting> </security-settings>
-
Open the
BROKER_INSTANCE_DIR/etc/login.config
file. - Locate and edit the appropriate alias block with the appropriate parameters (see the examples included below).
- Start or restart the broker (service or process)
Apache DS uses the OID
portion of DN path, however Microsoft AD does not. Microsoft AD uses the CN
portion instead.
For example; The DN path oid=testuser,dc=example,dc=com
would be used in Apache DS, while cn=testuser,dc=example,dc=com
would be used in Microsoft AD.
Example 10.7. Example Apache DS login.conf
configuration
activemq { org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required debug=true 1 initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory 2 connectionURL="ldap://localhost:10389" 3 connectionUsername="uid=admin,ou=system" 4 connectionPassword=secret 5 connectionProtocol=s 6 authentication=simple 7 userBase="dc=example,dc=com" 8 userSearchMatching="(uid={0})" 9 userSearchSubtree=true 10 userRoleName= 11 roleBase="dc=example,dc=com" 12 roleName=cn 13 roleSearchMatching="(member={0})" 14 roleSearchSubtree=true 15 ; };
Example 10.8. Example Microsoft Active Directory login.conf
Configuration
activemq { org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required debug=true initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory connectionURL="LDAP://localhost:389" connectionUsername="CN=Administrator,CN=Users,DC=example,DC=com" connectionPassword=redhat.123 connectionProtocol=s authentication=simple userBase="dc=example,dc=com" userSearchMatching="(CN={0})" userSearchSubtree=true roleBase="dc=example,dc=com" roleName=cn roleSearchMatching="(member={0})" roleSearchSubtree=true ; };
- 1
- Toggle debugging on (
true
) or off (false
). Default isfalse
. - 2
- The
initialContextFactory
parameter must always be set tocom.sun.jndi.ldap.LdapCtxFactory
- 3
- Specify the location of the directory server using an ldap URL, ldap://Host:Port. One can optionally qualify this URL, by adding a forward slash,
/
, followed by the DN of a particular node in the directory tree. The default port of Apache DS is10389
while for Microsoft AD the default is389
. - 4
- The DN of the user that opens the connection to the directory server. For example,
uid=admin,ou=system
. Directory servers generally require clients to present username/password credentials in order to open a connection. - 5
- The password that matches the DN from
connectionUsername
. In the directory server, in the DIT, the password is normally stored as auserPassword
attribute in the corresponding directory entry. - 6
- Any value is supported but is effectively unused. This option must be set explicitly because it has no default value.
- 7
- Specify the authentication method used when binding to the LDAP server. This parameter can be set to either
simple
(which requires a username and password) ornone
(which allows anonymous access). - 8
- Select a particular subtree of the DIT to search for user entries. The subtree is specified by a DN, which specifies the base node of the subtree. For example, by setting this option to
ou=User,ou=ActiveMQ,ou=system
, the search for user entries is restricted to the subtree beneath theou=User,ou=ActiveMQ,ou=system
node. - 9
- Specify an LDAP search filter, which is applied to the subtree selected by
userBase
. See the Search Matching section below for more information. - 10
- Specify the search depth for user entries, relative to the node specified by
userBase
. This option is a boolean. A setting offalse
indicates it tries to match one of the child entries of theuserBase
node (maps tojavax.naming.directory.SearchControls.ONELEVEL_SCOPE
), whiletrue
indicates it tries to match any entry belonging to the subtree of theuserBase
node (maps tojavax.naming.directory.SearchControls.SUBTREE_SCOPE
). - 11
- Specify the name of the multi-valued attribute of the user entry that contains a list of role names for the user (where the role names are interpreted as group names by the broker’s authorization plug-in). If this option is omitted, no role names are extracted from the user entry.
- 12
- If role data is stored directly in the directory server, one can use a combination of role options (
roleBase
,roleSearchMatching
,roleSearchSubtree
, androleName
) as an alternative to (or in addition to) specifying theuserRoleName
option. This option selects a particular subtree of the DIT to search for role/group entries. The subtree is specified by a DN, which specifies the base node of the subtree. For example, by setting this option toou=Group,ou=ActiveMQ,ou=system
, the search for role/group entries is restricted to the subtree beneath theou=Group,ou=ActiveMQ,ou=system
node. - 13
- Specify the attribute type of the role entry that contains the name of the role/group (such as C, O, OU, etc.). If this option is omitted the role search feature is effectively disabled.
- 14
- Specify an LDAP search filter, which is applied to the subtree selected by
roleBase
. See the Search Matching section below for more information. - 15
- Specify the search depth for role entries, relative to the node specified by
roleBase
. If set tofalse
(which is the default) the search tries to match one of the child entries of theroleBase
node (maps tojavax.naming.directory.SearchControls.ONELEVEL_SCOPE
). Iftrue
it tries to match any entry belonging to the subtree of the roleBase node (maps tojavax.naming.directory.SearchControls.SUBTREE_SCOPE
).
Search Matching
- userSearchMatching
Before passing to the LDAP search operation, the string value provided in this configuration parameter is subjected to string substitution, as implemented by the
java.text.MessageFormat
class.
This means that the special string,
{0}
, is substituted by the username, as extracted from the incoming client credentials. After substitution, the string is interpreted as an LDAP search filter (the syntax is defined by the IETF standard RFC 2254).
For example, if this option is set to
(uid={0})
and the received username isjdoe
, the search filter becomes(uid=jdoe)
after string substitution.
If the resulting search filter is applied to the subtree selected by the user base,
ou=User,ou=ActiveMQ,ou=system
, it would match the entry,uid=jdoe,ou=User,ou=ActiveMQ,ou=system
.
A short introduction to the search filter syntax is available from Oracle’s JNDI tutorial
- roleSearchMatching
This works in a similar manner to the
userSearchMatching
option, except that it supports two substitution strings.
The substitution string
{0}
substitutes the full DN of the matched user entry (that is, the result of the user search). For example, for the user,jdoe
, the substituted string could beuid=jdoe,ou=User,ou=ActiveMQ,ou=system
.
The substitution string
{1}
substitutes the received username. For example,jdoe
.
If this option is set to
(member=uid={1})
and the received username isjdoe
, the search filter becomes(member=uid=jdoe)
after string substitution (assuming ApacheDS search filter syntax).
If the resulting search filter is applied to the subtree selected by the role base,
ou=Group,ou=ActiveMQ,ou=system
, it matches all role entries that have amember
attribute equal touid=jdoe
(the value of amember
attribute is a DN).
This option must always be set, even if role searching is disabled, because it has no default value. If OpenLDAP is used, the syntax of the search filter is
(member:=uid=jdoe)
.
10.2.2. Configure LDAP Authorization
The LegacyLDAPSecuritySettingPlugin
security-setting-plugin will read the security information that was previously handled by LDAPAuthorizationMap
and the cachedLDAPAuthorizationMap
in Apache A-MQ 6 and turn it into corresponding security settings
where possible.
The security implementations of the two brokers do not match perfectly so some translation must occur to achieve near equivalent functionality.
Here is an example of the plugin’s configuration:
<security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin"> 1 <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/> 2 <setting name="connectionURL" value="ldap://localhost:1024"/> 3 <setting name="connectionUsername" value="uid=admin,ou=system"/> 4 <setting name="connectionPassword" value="secret"/> 5 <setting name="connectionProtocol" value="s"/> 6 <setting name="authentication" value="simple"/> 7 </security-setting-plugin>
- 1
class-name
. The implementation isorg.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin
.- 2
initialContextFactory
. The initial context factory used to connect to LDAP. It must always be set tocom.sun.jndi.ldap.LdapCtxFactory
(that is, the default value).- 3
connectionURL
. Specifies the location of the directory server using an LDAP URL,ldap://Host:Port
. You can optionally qualify this URL, by adding a forward slash,/
, followed by the DN of a particular node in the directory tree. For example,ldap://ldapserver:10389/ou=system
. The default isldap://localhost:1024
.- 4
connectionUsername
. The DN of the user that opens the connection to the directory server. For example,uid=admin,ou=system
. Directory servers generally require clients to present username/password credentials in order to open a connection.- 5
connectionPassword
. The password that matches the DN fromconnectionUsername
. In the directory server, in the DIT, the password is normally stored as auserPassword
attribute in the corresponding directory entry.- 6
connectionProtocol
- any value is supported but is effectively unused. In the future, this option may allow one to select the Secure Socket Layer (SSL) for the connection to the directory server. This option must be set explicitly because it has no default value.- 7
authentication
. Specifies the authentication method used when binding to the LDAP server. Can take either of the values,simple
(username and password, the default value) ornone
(anonymous). Note: Simple Authentication and Security Layer (SASL) authentication is currently not supported.
Other possible settings not shown in the example above are:
destinationBase
-
Specifies the DN of the node whose children provide the permissions for all destinations. In this case the DN is a literal value (that is, no string substitution is performed on the property value). For example, a typical value of this property is
ou=destinations,o=ActiveMQ,ou=system
(that is, the default value). filter
-
Specifies an LDAP search filter, which is used when looking up the permissions for any kind of destination. The search filter attempts to match one of the children or descendants of the queue or topic node. The default value is
(cn=*)
. roleAttribute
-
Specifies an attribute of the node matched by
filter
whose value is the DN of a role. Default value isuniqueMember
. adminPermissionValue
-
Specifies a value that matches the
admin
permission. The default value isadmin
. readPermissionValue
-
Specifies a value that matches the
read
permission. The default value isread
. writePermissionValue
-
Specifies a value that matches the
write
permission. The default value iswrite
. enableListener
-
Whether or not to enable a listener that will automatically receive updates made in the LDAP server and update the broker’s authorization configuration in real-time. The default value is
true
.
The name of the queue or topic defined in LDAP will serve as the "match" for the security-setting, the permission value will be mapped from the A-MQ 6 type to the AMQ 7 type, and the role will be mapped as-is. Since the name of the queue or topic coming from LDAP will server as the "match" for the security-setting the security-setting may not be applied as expected to JMS destinations since AMQ 7 always prefixes JMS destinations with "jms.queue." or "jms.topic." as necessary.
A-MQ 6 only has three permission types - read
, write
, and admin
. These permission types are described on the ActiveMQ website; http://activemq.apache.org/security.html.
However, as described previously, AMQ 7 has 10 permission types:
-
createAddress
-
deleteAddress
-
createDurableQueue
-
deleteDurableQueue
-
createNonDurableQueue
-
deleteNonDurableQueue
-
send
-
consume
-
manage
-
browse
The list below shows how the old types are mapped to the new types:
-
read
-consume
,browse
-
write
-send
-
admin
-createDurableQueue
,deleteDurableQueue
,createNonDurableQueue
,deleteNonDurableQueue
,createAddress
,deleteAddress
As mentioned, there are a few places where a translation was performed to achieve some equivalence:
-
This mapping does not include the AMQ 7
manage
permission type since there is no type analogous for that in A-MQ 6. -
The
admin
permission in A-MQ 6 relates to whether or not the broker will auto-create a destination if it does not exist and the user sends a message to it. AMQ 7 automatically allows the automatic creation of a destination if the user has permission to send message to it. Therefore, the plugin will map theadmin
permission to the four aforementioned permissions in AMQ 7.
10.3. Disabling Security
Security is enabled by default. Broker security can be enabled or disabled by setting the <security-enabled>
parameter in the <core>
element of the broker.xml
configuration file.
Procedure
-
Open the
broker.xml
file. -
Locate the
<security-enabled>
parameter. Edit the entry as needed
Set the parameter to
false
to disable security:<security-enabled>false</security-enabled>
-
If necessary, change the
security-invalidation-interval
entry (which periodically invalidates secure logins) to a different value (in ms). The default is10000
.