Jadice Server JMS-Schnittstelle mit TLS absichern

Step-by-step guide

Um die JMS-Schnittstelle von jadice server über TLS abzusichern müssen zwei Dinge angepasst werden.

  1. Der embedded ActiveMQ-Broker, den jadice server mitbringt, muss so konfiguriert werden, dass dieser die für die Verschlüsselung benötigten Keystores kennt. Dazu in der Datei server-config/application/embedded-activemq-broker.xml in der Bean "broker" folgenden Eintrag ergänzen:

    jetty-tls.xml
        <amq:sslContext>
          <amq:sslContext
              keyStore="C:\path\to\your\keystore.jks" keyStorePassword="test"
              trustStore="C:\path\to\your\cacerts" trustStorePassword="changeit"/>
        </amq:sslContext>

    Beachten Sie bitte, dass für den Keystore der absolute Pfad im Dateisystem angegeben werden muss.

  2. Ebenfalls in der Datei server-config/application/embedded-activemq-broker.xml die Zeile

    <amq:transportConnector name="nio" uri="nio://0.0.0.0:${jadice.server.activemq-port}" discoveryUri="multicast://default?group=${jadice.server.activemq-group}" />

    durch folgende, um das Protokoll "ssl" erweiterte, ersetzen: 

    <amq:transportConnector name="nio+ssl" uri="nio+ssl://0.0.0.0:${jadice.server.activemq-port}" discoveryUri="multicast://default?group=${jadice.server.activemq-group}" />

    Nun kann der Server von einem Client über SSL angesprochen werden, z.B. ssl://localhost:61616

Die komplette Datei mit Anpassungen: embedded-activemq-broker.xml


Passwörter absichern 

Im obigen Beispiel stehen die Passwörter im Klartext in der Konfigurationsdatei. Dies ist natürlich für Produktionsumgebungen nicht zu empfehlen. ActiveMQ bietet die Möglichkeit Passwörter durch Verschlüsselung abzusichern (siehe ActiveMQ - Encrypted passwords).

Beispiel mit dem Verschlüsselungspasswort "activemq", dem Keystore-Passwort "test" und dem Truststore-Passwort "changeit":

  1. Verschlüsseln der Passwörter für den KeyStore und den TrustStore.

    $ apache-activemq/bin/activemq encrypt --password activemq --input test --algorithm PBEWithMD5AndDES
    ...
    Encrypted text: ZFNmPbPmkaGnqXqRl6+7KA== 
    
    $ apache-activemq/bin/activemq encrypt --password activemq --input changeit --algorithm PBEWithMD5AndDES
    ...
    Encrypted text: OpGztxCdz63JkKD0mYWLDpWq/+nzR7H7
  2. Passwörter in der Datei server-config/application/embedded-activemq-broker.xml durch Properties ersetzen:

    jetty-tls.xml
        <amq:sslContext>
          <amq:sslContext
              keyStore="C:\path\to\your\keystore.jks" keyStorePassword="${jadice.server.activemq.keystore.password}"
              trustStore="C:\path\to\your\cacerts" trustStorePassword="${jadice.server.activemq.truststore.password}"/>
        </amq:sslContext>
    

    Die komplette Datei mit den Anpassungen: embedded-activemq-broker.xml

  3. In der Datei server-config/application/server.xml werden die verschlüsselten Passwörter nun als Properties hinterlegt. Außerdem wird der PropertyLoader so konfiguriert, dass er die Properties mithilfe des Verschlüssellungs-Passworts aus einer Umgebungsvariablen entschlüsseln kann. Dazu werden die beiden neuen Beans "environmentVariablesConfiguration" und "configurationEncryptor" definiert, sowie die vorhandene Bean "propertyConfigurer" (mit der Klasse PropertyPlaceholderConfigurer) wie folgt angepasst:

    Ergänzung in server.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.spring4.properties.EncryptablePropertyPlaceholderConfigurer">
        <constructor-arg ref="configurationEncryptor" />
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        <property name="searchSystemEnvironment" value="true" />
    
        <property name="properties">
          <props>
          	<!--
          	  Name of the JMS request queue for new job requests;
          	  Reference to the default queue name as defined in class JMSJobFactory
          	-->
            <prop key="jadice.server.queue-name">
              #{T(com.levigo.jadice.server.jms.client.JMSJobFactory).DEFAULT_QUEUE_NAME}
            </prop>
            
            <!-- 
            	Active MQ specific values: AMQ TCP Port and group name.
            	These values can be dropped if another MOM is configured below.
             -->
            <prop key="jadice.server.activemq-port">61616</prop>
            <prop key="jadice.server.activemq-group">jadice-server.cluster</prop>
            <prop key="jadice.server.activemq.keystore.password">ENC(ZFNmPbPmkaGnqXqRl6+7KA==)</prop>
            <prop key="jadice.server.activemq.truststore.password">ENC(OpGztxCdz63JkKD0mYWLDpWq/+nzR7H7)</prop>
          </props>
        </property>
      </bean>

    Die komplette Datei mit den Anpassungen: server.xml

  4. Eine Umgebungsvariable für das Verschlüsselungspasswort anlegen. 

    # unter linux
    $ export ACTIVEMQ_ENCRYPTION_PASSWORD=activemq
    # unter Windows
    # z.B. über die GUI: Systemsteuerung\System und Sicherheit\System > Erweiterte Systemeinstellungen > Umgebungsvariablen > Systemvariablen "Neu"

Bouncy Castle

Um modernere Verschlüsselungsalgorithmen zu verwenden, kann z.B. ein Bouncy Castle JCE Provider verwendet werden.

Beispiel Bouncy Castle
  <bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
    <property name="algorithm" value="PBEWITHSHA256AND128BITAES-CBC-BC" />
    <property name="passwordEnvName" value="ACTIVEMQ_ENCRYPTION_PASSWORD" />
  </bean>

  <bean id="jceProvider" class="org.bouncycastle.jce.provider.BouncyCastleProvider">
  </bean>

  <bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
    <property name="config" ref="environmentVariablesConfiguration" />
    <property name="provider" ref="jceProvider" />
  </bean>

Die Verschlüsselung in Java könnte etwa so aussehen (vgl. Using Jasypt with the Bouncy Castle JCE provider)

encryption with bouncy castle
  public static void main(String[] args) {

    StandardPBEStringEncryptor myFirstEncryptor = new StandardPBEStringEncryptor();
    myFirstEncryptor.setProvider(new BouncyCastleProvider());
    myFirstEncryptor.setAlgorithm("PBEWITHSHA256AND128BITAES-CBC-BC");
    myFirstEncryptor.setPassword("activemq");

    String keyStorePassword = myFirstEncryptor.encrypt("test");
    String trustStorePassword = myFirstEncryptor.encrypt("changeit");
    System.out.println("keyStorePassword: " + keyStorePassword);
    System.out.println("trustStorePassword " + trustStorePassword);

  }

Weitere Informationen

Informationen zu den Einstellungen können Sie der Dokumentation von ActiveMQ entnehmen:

Treten Probleme bei der Aktivierung von TLS auf, hilft die System-Property -Djavax.net.debug=all oft weiter, um das Problem einzugrenzen. Diese Einstellung kann in der Datei wrapper/wrapper.conf eingetragen werden. Oracle bietet einen ausführlichen Artikel zum Thema "Debugging SSL/TLS Connections" an.