Apache ActiveMQ absichern


Apaches ActiveMQ wird häufig für Integrationslösungen verwendet. Sie entkoppelt Prozesse und verbindet Komponenten. Gerade wenn unterschiedlichste Komponenten über eine zentrale Stelle miteinander kommunizieren ist jedoch Vorsicht geboten. Aus Sicherheitsgründen kann es erforderlich sein, dass Queues gegenüber bestimmten Komponenten abgesichert sind. ActiveMQ bietet hierfür einfach bis komplexe Lösungen an, auf die ich in diesem Beitrag eingehen möchte.

Authentifizierung

Wie so oft müssen wir zwischen Authentifizierung und Autorisierung unterscheiden. Das simpleAuthenticationPlugin beispielsweise bietet eine einfache Lösung um Benutzer zu Authentifizieren. Dabei wird geprüft ob ein Benutzer auch der ist, als der er sich ausgibt. Dies geschieht durch ein Passwort. Das simpleAuthenticationPlugin wird in die Liste der Plugins des jeweiligen Brokers geschrieben. Bei der Standardinstallation von ActiveMQ gibt es nur einen Broker. Dieser ist in activemq.xml deklariert. Es können aber auch andere Broker in den Spring-Context geladen worden sein.

<broker>
...
  <plugins>
    <simpleAuthenticationPlugin anonymousAccessAllowed="true">
      <users>
        <authenticationUser username="admin" password="admin" groups="users,admins"/>
        <authenticationUser username="user" password="password" groups="users"/>
      </users>
    </simpleAuthenticationPlugin>
  </plugins>
</broker>

Für jeden Benutzer muss das Passwort und dessen Gruppe angegeben werden. Gruppen ergeben sich dynamisch und müssen nicht explizit erstellt werden.
Durch das Attribut anonymousAccessAllowed kann bestimmt werden ob anonyme Benutzer ohne Passwort Zugriff auf den Broker haben. Anonyme Benutzer sind der Gruppe anonymous zugeteilt.

JAAS Plugin

Neben dem simpleAuthenticationPlugin werden weitere Plugins wie das jaasAuthenticationPlugin angeboten. Der Java Authentication and Authorization Service (JAAS) unterstützt dabei weitaus komplexere Konfigurationsmöglichkeiten.

<broker>
...
<plugins>
    <jaasAuthenticationPlugin configuration="activemq" />
</plugins>

Der Parameter configuration gibt dabei den Namen der zu Verwendenden Konfiguration an, welche sich in der login.config befindet.

Eine einfache Benutzername-Passwort-Authentifizierung ist beispielsweise durch das PropertiesLoginModule möglich.

activemq {
    org.apache.activemq.jaas.PropertiesLoginModule required
        debug=true
        org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties"
        org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties";
};

In diesem Beispiel wird auf die Property-Dateien users.properties und groups.properties verwiesen.

Die users.properties ist eine simple Key-Value-Map für Benutzername und Passwort

admin=admin
user=password

In der groups.properties werden wiederum die Benutzer in Gruppen zugeordnet. Mit diesen Gruppen ist es dann möglich Rechte für Queues zu vergeben, wie wir gleich sehen werden.

admins=admin
users=user

Autorisierung

Die Autorisierung erfolgt ebenfalls über ein Broker-Plugin. Das authorizationPlugin arbeitet mit drei Berechtigungsleveln. read, write und admin.

readErlaubt das Lesen von Queues. Lesen ist dabei gleichzusetzen mit dem Löschen einer Nachricht. Explizites Löschen gibt es nicht als Berechtigung.
writeErlaubt es Nachrichten in eine Queue zu schreiben. Diese Aktion ist nur für existierende Queues möglich.
adminErlaubt es neue Queues anzulegen.
<broker>
...
  <plugins>
    <authorizationPlugin>
      <map>
        <authorizationMap>
          <authorizationEntries>
            <authorizationEntry queue=">" read="admins" write="admins" admin="admins"/>
            <authorizationEntry topic=">" read="admins" write="admins" admin="admins"/>

            <authorizationEntry queue="USERS.>" read="users" write="users" admin="users"/>

            <authorizationEntry topic="ActiveMQ.Advisory.>" read="users" write="users" admin="users"/>
          </authorizationEntries>
          <tempDestinationAuthorizationEntry>
            <tempDestinationAuthorizationEntry read="admins" write="admins" admin="admins"/>
          </tempDestinationAuthorizationEntry>
        </authorizationMap>
      </map>
    </authorizationPlugin>
  </plugins>
</broker>

In der hier gezeigten Konfiguration wird der Gruppe admins das Recht auf alle Queues und Topics gegeben. Das Wildcard > sagt dabei aus, dass das Recht für alle Pfade nach dem > gilt. Möchte man nur Berechtigungen bis zum nächsten Punkt . einräumen, so benutzt man das Wildcard *.

Der Gruppe users werden Rechte eingeräumt für Queues die mit USERS. beginnen. Wichtig dabei. Auch admins haben ebenfalls auf USERS. Zugriff, da > diese mit einschließt. Einmal vergebene Rechte können für einen präziseren Pfad später nicht mehr entfernt werden.

Fast alle Aktionen müssen im Audit-Log ActiveMQ.Advisory.> hinterlegt werden. Es ist daher sinnvoll jeder Gruppe Schreibrechte darauf einzuräumen. Eine granularere Beschreibung findet sich hier.

Der Tag tempDestinationAuthorizationEntry spezifiziert welche Gruppen temporäre Queues anlegen dürfen.

Verschlüsselung

Die Verschlüsselung erfolgt über den EncryptablePropertyPlaceholderConfigurer. Dieser ersetzt den PropertyPlaceholderConfigurer, welche für das laden von einfachen Properties verantwortlich ist. Diese Bean befindet sich für gewöhnlich in der activemq.xml.

<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
  <property name="algorithm" value="PBEWithMD5AndDES" />
  <property name="passwordEnvName" value="ACTIVEMQ\_ENCRYPTION\_PASSWORD" />
</bean>
                                                                     
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
  <property name="config" ref="environmentVariablesConfiguration" />
</bean> 
    
<bean id="propertyConfigurer" class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer"> 
  <constructor-arg ref="configurationEncryptor" /> 
  <property name="location" value="file:${activemq.base}/conf/credentials-enc.properties"/> 
</bean>

In diesem Beispiel wird anstelle der credentials.properties die credentials-enc.properties geladen. Beide Dateien können die gleichen Inhalte besitzen. Verschlüsselte Passwörter werden jedoch mit ENC(…) deklariert.

myValue=ENC(abcdefghijk)

Alle Passwörter müssen mit einem Passwort verschlüsselt werden. In dem oberen Beispiel wird dies in der Environment-Variable ACTIVEMQ_ENCRYPTION_PASSWORD hinterlegt. Wenn anstelle des Properties passwordEnvName einfach password verwendet wird, kann auch direkt in der XML-Datei das Passwort hinterlegt werden.

Um ein Passwort zu verschlüsseln kann die Binary der ActiveMQ verwendet werden.

bin/activemq encrypt --MyEncryptionPassword activemq --input mypassword

Die verschlüsselten Properties können dann ganz einfach anstelle der Passwörter im simpleAuthenticationPlugin verwendet werden.

<authenticationUser username="system" password="${myValue}" groups="users,admins"/>

Webconsole

Die Webconsole stellt ein Interface bereit, mit dem Queues über den Browser verwaltet werden können.

Die Passwörter für das Login der Webconsole werden in der Datei jetty-realm.properties in der Form Benutzername: Passwort, Role gespeichert.

admin: admin, admin

Wichtig dabei ist, dass das Login in die Webconsole nichts mit dem Passwort für den Broker zu tun hat. Die Webconsole muss sich jedoch ebenfalls bei dem Broker anmelden. Dies geschieht über die Properties activemq.username und activemq.password in der credentials.properties.

Auch für den Login der Webconsole können die Properties verschlüsselt werden. Hierzu muss der oben bereits beschriebene EncryptablePropertyPlaceholderConfigurer in der Datei webapps/admin/WEB-INF/webconsole-embeded.xml ebenfalls hinterlegt werden.