{{announcement.body}}
{{announcement.title}}

Deploying Artemis Broker With SSL Enabled and Use AMQP

DZone 's Guide to

Deploying Artemis Broker With SSL Enabled and Use AMQP

Learn how to deploy the Red Hat AMQ Broker on openshift 4.x. The external client can connect to produce/consume messages using AMQP.

· Integration Zone ·
Free Resource

Red Hat AMQ Broker

AMQ Broker is based on Apache ActiveMQ Artemis. It provides a message broker that is JMS-compliant. Apache ActiveMQ Artemis is an open-source project for an asynchronous messaging system. It is a high performance, embeddable, clustered, and supports multiple protocols.

The core ActiveMQ Artemis is JMS-agnostic and provides a non-JMS API, which is referred to as the core API. ActiveMQ Artemis also provides a JMS client API that uses a facade layer to implement the JMS semantics on top of the core API. Essentially, JMS interactions are translated into core API operations on the client-side using the JMS client API. From there, all operations are sent using the core client API and Apache ActiveMQ Artemis wire format. The server itself only uses the core API. For more details on the core API and its concepts, refer to the ActiveMQ Artemis documentation.

Red Hat Open Shift

Red Hat Open Shift offers a consistent hybrid-cloud foundation for building and scaling containerized applications. Open Shift provides an enterprise-grade, container-based platform with no vendor lock-in. Red Hat was one of the first companies to work with Google on Kubernetes, even before launch, and has become the second leading contributor to the Kubernetes upstream project. Open Shift also provides a common development platform no matter what infrastructure we use to host the application.

AMQP

The Advanced Message Queuing Protocol (AMQP) is an open standard application layer protocol for message-oriented middleware. The defining features of AMQP are message orientation, queuing, routing (including point-to-point and publish-and-subscribe), reliability and security.

In this article we will deploy the Red Hat AMQ Broker 7.7 on openshift 4.3 with SSL security enabled and produce consume messages from the external clients using AMQP protocol.

Prerequisites

For this demonstration, you will need the following technologies set up in your development environment:

  1. An Open Shift 4.3+ environment with Cluster Admin access
  2. Open shift CLI (oc)
  3. Apache Maven 3.6.3+
  4. JDK 8+ Installed

There are two ways to deploy AMQ Broker on Open Shift Container Platform:

The AMQ Broker Operator is the recommended way to create broker deployments on Open Shift Container Platform. we will be using AMQ Broker Operator  to deploy the AMQ Broker

Deploy AMQ Broker on Open Shift

  1. In your web browser, navigate to the AMQ Broker Software Downloads page.
  2. In the Version drop-down box, ensure that the value is set to the latest AMQ Broker version, 7.7.0.
  3. Next to AMQ Broker 7.7 Operator Installation Files, click Download.

    Download of the amq-broker-operator-7.7.0-ocp-install-examples.zip compressed archive automatically begins.

  4. When the download has completed, move the archive to your chosen installation directory

  5. Log in to the Open Shift Container Platform as a cluster administrator.

Install AMQBrokerOperator

1. Create a new project

Java
 




x


1
oc new-project new-message-project



2. Specify a service account to use with the Operator

3. Create a service account in your project.

Java
 




x


 
1
$ oc create -f deploy/service_account.yaml
2
 
          



4. Create a role in your project. This file specifies the resources that the Operator can use and modify.

Java
 




xxxxxxxxxx
1


1
oc create -f deploy/role.yaml



5. Create the role binding in your project. The role binding binds the previously-created service account to the Operator role, based on the names you specified

Java
 




xxxxxxxxxx
1


 
1
oc create -f deploy/role_binding.yaml


  

6. Install the latest CRDs in your Open Shift cluster before deploying and starting the Operator

Deploy the main broker CRD, address CRD, and scale down controller CRD.

Java
 




xxxxxxxxxx
1


 
1
oc create -f deploy/crds/broker_activemqartemis_crd.yaml
2
oc create -f deploy/crds/broker_activemqartemisaddress_crd.yaml
3
oc create -f deploy/crds/broker_activemqartemisscaledown_crd.yaml



7. Create Imagepullsecret and associate with the account used for authentication in the Red Hat Container Registry with the default, deployer, and builder service accounts for your Open Shift project.

Java
 




xxxxxxxxxx
1


1
oc create secret docker-registry imagestreamsecret   --docker-server=registry.redhat.io   --docker-username=   --docker-password=   --docker-email=
2
  
3
oc secrets link --for=pull default imagestreamsecret
4
oc secrets link --for=pull deployer imagestreamsecret
5
oc secrets link --for=pull builder imagestreamsecret
6
 
          
7
[kkakarla@kkakarla /]$ oc get secrets | grep imagestreamsecret
8
imagestreamsecret                     kubernetes.io/dockerconfigjson        1      22h
9
 
          



8. Deploy the Operator

Java
 




xxxxxxxxxx
1


1
oc create -f deploy/operator.yaml
2
[kkakarla@kkakarla /]$ oc get pods | grep operator
3
amq-broker-operator-85598678bf-l9c2g   1/1     Running   0          22h
4
 
          


    

9. Now Deploy the AMQ Artemis SSL enabled broker

Add the protocols and port parameters. Set values to specify the messaging protocols to be used by the acceptor and the port on each broker Pod to expose for those protocols

The configured acceptor exposes port 5672 to AMQP clients, Core protocol to the core, Open Wire to openwire, MQTT to MQTT and STOMP to stomp

For each broker Pod in your deployment, the Operator also creates a default acceptor that uses port 61616. This default acceptor is required for broker clustering and has the Core protocol enabled.

By default, the AMQ Broker management console uses port 8161 on the broker Pod. Each broker Pod in your deployment has a dedicated service that provides access to the console

To specify the number of concurrent client connections that the acceptor allows, add the connections Allowed parameter and set a value

By default, an acceptor is exposed only to clients in the same Open Shift cluster as the broker deployment. To also expose the acceptor to clients outside Open Shift, add the expose parameter and set the value to true.

Also, to enable secure connections to the acceptor from clients outside Open Shift, add the sslEnabled parameter and set the value to true

Configuring One-Way TLS

The procedure in this section shows how to configure one-way Transport Layer Security (TLS) to secure a broker-client connection.

In one-way TLS, only the broker presents a certificate. This certificate is used by the client to authenticate the broker

1. Generate a self-signed certificate for the broker key store.

Java
 




xxxxxxxxxx
1


 
1
keytool -genkey -alias broker -keyalg RSA -keystore /home/kkakarla/development/amq7/amq7-on-openshift/broker.ks



2. Export the certificate from the broker key store, so that it can be shared with clients. Export the certificate in the Base64-encoded .pem format

Java
 




xxxxxxxxxx
1


1
keytool -export -alias broker -keystore /home/kkakarla/development/amq7/amq7-on-openshift/broker.ks -file /home/kkakarla/development/amq7/amq7-on-openshift/broker_cert.pem



3. On the client, create a client trust store that imports the broker certificate

Java
 




xxxxxxxxxx
1


 
1
keytool -import -alias broker -keystore /home/kkakarla/development/amq7/amq7-on-openshift/client.ts -file /home/kkakarla/development/amq7/amq7-on-openshift/broker_cert.pem



4. Create a secret to store the TLS credentials

Java
 




xxxxxxxxxx
1


1
oc create secret generic amq7brokersecret \
2
--from-file=broker.ks=/home/kkakarla/development/amq7/amq7-on-openshift/broker.ks \
3
--from-file=client.ts=/home/kkakarla/development/amq7/amq7-on-openshift/broker.ks \
4
--from-literal=keyStorePassword=artemis7 \
5
--from-literal=trustStorePassword=artemis7
6
 
          
7
[kkakarla@kkakarla /]$ oc get secrets | grep amq7brokersecret
8
amq7brokersecret                      Opaque                                4      23h



5. Add the secret to the service account that you created when installing the Operator. 

Java
 




xxxxxxxxxx
1


1
oc secrets add sa/amq-broker-operator secret/amq7brokersecret



6. Specify the secret name in the sslSecret parameter of your secured acceptor or connector

7. Now deploy the broker

Java
 




xxxxxxxxxx
1
16


1
apiVersion: broker.amq.io/v2alpha2
2
kind: ActiveMQArtemis
3
metadata:
4
  name: ex-aao
5
spec:
6
  deploymentPlan:
7
    size: 1
8
    image: registry.redhat.io/amq7/amq-broker:7.7
9
  acceptors:
10
  - name: amqp
11
    protocols: amqp,openwire
12
    port: 5672
13
    sslEnabled: true
14
    sslSecret: amq7brokersecret
15
    expose: true
16
    connectionsAllowed: 25



8. Now check all the project resources

Shell
 




xxxxxxxxxx
1
23


1
[kkakarla@kkakarla /]$ oc get all
2
NAME                                       READY   STATUS    RESTARTS   AGE
3
pod/amq-broker-operator-85598678bf-l9c2g   1/1     Running   0          23h
4
pod/ex-aao-ss-0                            1/1     Running   0          23h
5
 
          
6
NAME                          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)              AGE
7
service/amq-broker-operator   ClusterIP   0.0.0.0          <none>        8383/TCP             23h
8
service/ex-aao-amqp-0-svc     ClusterIP   0.0.0.0          <none>        5672/TCP             23h
9
service/ex-aao-hdls-svc       ClusterIP   None             <none>        8161/TCP,61616/TCP   23h
10
service/ex-aao-ping-svc       ClusterIP   None             <none>        8888/TCP             23h
11
 
          
12
NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
13
deployment.apps/amq-broker-operator   1/1     1            1           23h
14
 
          
15
NAME                                             DESIRED   CURRENT   READY   AGE
16
replicaset.apps/amq-broker-operator-85598678bf   1         1         1       23h
17
 
          
18
NAME                         READY   AGE
19
statefulset.apps/ex-aao-ss   1/1     23h
20
 
          
21
NAME                                             HOST/PORT                                                                                PATH   SERVICES            PORT     TERMINATION        WILDCARD
22
route.route.openshift.io/ex-aao-amqp-0-svc-rte   ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com          ex-aao-amqp-0-svc   amqp-0   passthrough/None   None
23
 
          



Connecting to the Broker From External Clients

When you expose an acceptor to external clients (that is, by setting the value of the expose parameter to true), a dedicated Service and Route are automatically created for each broker Pod in the deployment

An external client can connect to the broker by specifying the full hostname of the Route created for the broker Pod

By default, the Open Shift router listens to port 80 for non-secured (that is, non-SSL) traffic and port 443 for secured (that is, SSL-encrypted) traffic. For an HTTP connection, the router automatically directs traffic to port 443 if you specify a secure connection URL, or to port 80 if you specify a non-secure connection URL

Clients must explicitly specify the port number (for example, port 443) as part of the connection URL.

For one-way TLS, the client must specify the path to its trust store and the corresponding password, as part of the connection URL.

To Produce Messages using amqps

Java
 




xxxxxxxxxx
1
13


1
 public void amqpTest() throws Exception{
2
 
          
3
        JmsConnectionFactory activeMQConnectionFactory = new JmsConnectionFactory("user-name","password","amqps://ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com:443?" +
4
                "transport.trustStoreLocation=/home/kkakarla/development/amq7/amq7-on-openshift/client.ts&transport.keyStoreLocation=/home/kkakarla/development/amq7/amq7-on-openshift/broker.ks" +
5
                "&transport.trustStorePassword=artemis7&transport.keyStorePassword=artemis7&transport.verifyHost=false");
6
        Connection connection = activeMQConnectionFactory.createConnection();
7
        connection.start();
8
        Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
9
        MessageProducer messageProducer = session.createProducer(session.createQueue("test_q"));
10
        Message message = session.createTextMessage("this is amqp two way ssl testing");
11
        messageProducer.send(message);
12
        connection.close();
13
    }



For simplicity. I defined the above class as a bean and called from the camel route.

Java
 




xxxxxxxxxx
1
16


1
 
          
2
<bean id="amqpTest" class="com.mycompany.camel.AmqpsslExample"></div>
3
<camelContext id="_camelContext1"
4
        xmlns="http://camel.apache.org/schema/spring">
5
    
6
      <route>
7
      <from uri="timer:foo?period=5000&amp;repeatCount=1"></from>
8
      <setBody>
9
          <method ref="amqpTest" method="amqpTest"></method>
10
      </setBody>
11
      <log message="The message sent"></log>
12
      <to uri="mock:result"></to>
13
    </route>   
14
    
15
  
16
  



To Consume Messages using amqps.

Java
 




xxxxxxxxxx
1
16


1
 public void amqpTestConsumer() throws Exception{
2
 
          
3
        JmsConnectionFactory activeMQConnectionFactory = new JmsConnectionFactory("user-name","password","amqps://ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com:443?" +
4
                "transport.trustStoreLocation=/home/kkakarla/development/amq7/amq7-on-openshift/client.ts&transport.keyStoreLocation=//home/kkakarla/development/amq7/amq7-on-openshift/broker.ks" +
5
                "&transport.trustStorePassword=artemis7&transport.keyStorePassword=artemis7&transport.verifyHost=false");
6
        Connection connection = activeMQConnectionFactory.createConnection();
7
        connection.start();
8
        Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
9
        // Step 5. create a moving receiver, this means the message will be removed from the queue
10
        MessageConsumer consumer = session.createConsumer(session.createQueue("test_q"));
11
 
          
12
        // Step 7. receive the simple message
13
        TextMessage m = (TextMessage) consumer.receive(5000);
14
        System.out.println("message = " + m.getText());
15
        connection.close();
16
    }



camel consumer route

Java
 




x


1
 <route >
2
      <from uri="timer:foo?period=5000&amp;repeatCount=1"/>
3
      <setBody>
4
          <method ref="amqpTest" method="amqpTestConsumer()"/>
5
      </setBody>
6
      <to uri="mock:result"/>
7
    </route> 



Now Run the Test case to connect the AMQ Broker deployed on openshift and  produce/consume messages

Java
 




xxxxxxxxxx
1
12


 
1
[kkakarla@kkakarla camel-artemis-openshiftexample]$ mvn camel:run
2
[INFO] Scanning for projects...
3
[INFO] 
4
[INFO] ----------------< com.mycompany:camel-artemis-example1 >----------------
5
[INFO] Building Fuse CBR Quickstart - Java 1.0.0-SNAPSHOT
6
[INFO] -------------------------------[ bundle ]-------------------------------
7
[INFO] 
8
---------------------------------------------------------------------------
9
----------------------------------------------------------------------------
10
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 started and consuming from: timer://foo?period=5000&repeatCount=1
11
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route2 started and consuming from: timer://foo?period=5000&repeatCount=1
12
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Total 2 routes, of which 2 are started
13
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Apache Camel 2.21.0.fuse-000077-redhat-1 (CamelContext: _camelContext1) started in 0.226 seconds
14
[pache.camel.spring.Main.main()] DefaultLifecycleProcessor      INFO  Starting beans in phase 2147483646
15
[b.upshift.rdu2.redhat.com:443]] SaslMechanismFinder            INFO  Best match for SASL auth was: SASL-PLAIN
16
[b.upshift.rdu2.redhat.com:443]] JmsConnection                  INFO  Connection ID:ae130afa-ffa9-4ba6-884f-2d40840d8421:1 connected to remote Broker: amqps://ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com:443?transport.trustStoreLocation=%2Fhome%2Fkkakarla%2Fdevelopment%2Famq7%2Famq7-on-openshift%2Fclient.ts&transport.keyStoreLocation=%2Fhome%2Fkkakarla%2Fdevelopment%2Famq7%2Famq7-on-openshift%2Fbroker.ks&transport.trustStorePassword=artemis7&transport.keyStorePassword=artemis7&transport.verifyHost=false
17
[text1) thread #2 - timer://foo] route1                         INFO  The message sent
18
[b.upshift.rdu2.redhat.com:443]] SaslMechanismFinder            INFO  Best match for SASL auth was: SASL-PLAIN
19
[b.upshift.rdu2.redhat.com:443]] JmsConnection                  INFO  Connection ID:c9b34adb-4355-49fb-a1e8-ef95a11e698e:1 connected to remote Broker: amqps://ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com:443?transport.trustStoreLocation=%2Fhome%2Fkkakarla%2Fdevelopment%2Famq7%2Famq7-on-openshift%2Fclient.ts&transport.keyStoreLocation=%2F%2Fhome%2Fkkakarla%2Fdevelopment%2Famq7%2Famq7-on-openshift%2Fbroker.ks&transport.trustStorePassword=artemis7&transport.keyStorePassword=artemis7&transport.verifyHost=false
20
message = this is amqp two way ssl testing
21
 
          



Similarly, we can connect using the open-wire protocol.

Java
 




xxxxxxxxxx
1
71


 
1
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQSslConnectionFactory">
2
 
          
3
        <property name="brokerURL" value="ssl://ex-aao-amqp-0-svc-rte-new-message-project.apps.xxx.redhat.com:443" />
4
 
          
5
        <property name="userName" value="7nRMRFDZ" />
6
 
          
7
        <property name="password" value="bFxUBMQJ" />
8
 
          
9
        <property name="trustStore" value="/home/kkakarla/development/amq7/amq7-on-openshift/client.ts" />
10
 
          
11
        <property name="trustStorePassword" value="artemis7" />
12
 
          
13
    </bean>    
14
 
          
15
      
16
 
          
17
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
18
 
          
19
        init-method="start" destroy-method="stop">
20
 
          
21
        <!-- maxConnections : Sets the maximum number of pooled Connection. Default = 1) -->
22
 
          
23
        <property name="maxConnections" value="10" />
24
 
          
25
        <!-- maximumActiveSessionPerConnection - The maximum number of active session per connection in the pool. -->
26
 
          
27
        <property name="maximumActiveSessionPerConnection" value="20" />
28
 
          
29
        <!-- blockIfSessionPoolIsFull : Controls behavior of session pool. Blocks call to Connection.getSession()
30
 
          
31
         if the session pool is full. Default = true -->
32
 
          
33
        <property name="blockIfSessionPoolIsFull" value="true" />
34
 
          
35
        <!-- createConnectionOnStartup - true to create a connection on startup. Used to warm-up the pool on startup.  -->
36
 
          
37
        <property name="createConnectionOnStartup" value="true" />
38
 
          
39
        <!-- idleTimeout : The maximum time a pooled Connection can sit unused before it is eligible for removal. Default=30sec -->
40
 
          
41
        <property name="idleTimeout" value="50" />
42
 
          
43
        <!-- connectionFactory : Sets the ConnectionFactory used to create new pooled Connections. -->
44
 
          
45
        <property name="connectionFactory" ref="activeMQConnectionFactory" />
46
 
          
47
    </bean>
48
   
49
 
          
50
 <bean id="jmsConfiguration" class="org.apache.camel.component.jms.JmsConfiguration">
51
 
          
52
        <property name="connectionFactory" ref="pooledConnectionFactory"/>
53
 
          
54
        <!-- concurrentConsumers : Maximum no.of concurrent invokers -->
55
 
          
56
        <property name="concurrentConsumers" value="5"/>
57
 
          
58
        <!-- maxConcurrentConsumers : Allows dynamic scaling for no.of concurrent invokers as well as dynamic shrinking back to the standard no.of consumers once the load decreases.-->
59
 
          
60
        <property name="maxConcurrentConsumers" value="10"/>
61
 
          
62
    </bean>
63
   
64
 
          
65
 <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
66
 
          
67
        <property name="configuration" ref="jmsConfiguration"/>
68
 
          
69
        <property name="deliveryPersistent" value="false" />
70
 
          
71
    </bean>
72
    <camelContext id="_camelContext1"
73
        xmlns="http://camel.apache.org/schema/spring">
74
        
75
        <route id="test1">
76
            <from id="testfrom1" uri="file:src/main/data?noop=true"/>
77
            <log id="test-1og1" message=" Transferring"/>
78
             <to id="test-to1" uri="direct:ExampleQueue"/>
79
            
80
        </route>
81
        
82
         <route>
83
            <from  uri="direct:ExampleQueue"/>
84
            <log  message=" Transferring to queue"/>
85
            <to  uri="activemq:queue:SCIENCEQUEUE"/>
86
        </route> 
87
        
88
         <route >
89
            <from  uri="activemq:queue:SCIENCEQUEUE"/>
90
            <log  message=" consuming from queue"/>
91
            <to  uri="file:src/out"/>
92
        </route>  
93
       
94
   </camelContext>
95
   
96
   



I hope it will help those who want to deploy the Red Hat AMQ Broker on openshift 4.x and the external client can connect to produce/consume messages using AMQP and open-wire protocols

Topics:
amqp, artemis, integration, open shift, ssl, tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}