4e21b72fc7e84285f8178a5f751c53035c77c024
[packages/precise/mcollective.git] / website / reference / integration / activemq_ssl.md
1 ---
2 layout: default
3 title: ActiveMQ TLS
4 toc: false
5 ---
6 [Security]: http://activemq.apache.org/security.html
7 [Registration]: /mcollective/reference/plugins/registration.html
8 [Wildcard]: http://activemq.apache.org/wildcards.html
9
10 In order to achieve end to end encryption we use TLS encryption between
11 ActiveMQ, the nodes and the client.
12
13 To set this up you need to Java Keystore, the instructions here work for Java
14 1.6 either Sun or OpenJDK based.
15
16 ## Full CA verified TLS between Stomp >= 1.2.2 and ActiveMQ
17 As of MCollective 2.0.0 and Stomp 1.2.2 it's possible to setup a TLS setup
18 that will only accept clients with certificates signed by a CA shared with
19 your clients and your ActiveMQ server like the one provided by Puppet.
20
21 You can only use this setup using the ActiveMQ specific connector plugin, not using
22 the generic Stomp one.
23
24 These examples will use the Puppet CA to generate the certificates but you can
25 use any CA as long as you have PEM format keys and certificates.
26
27 ### Create ActiveMQ certificates and keystores
28 With this setup we need the following:
29
30  * A certificate and keys for the ActiveMQ - we will call the ActiveMQ instance stomp.my.net
31  * A Certificate Authority certificate
32  * A key store for the ActiveMQ certificates
33  * A trust store instructing ActiveMQ what connections to trust
34
35 First we create the trust store, we load in our CA file which will instruct ActiveMQ
36 to trust any certificate signed by the Puppet CA. You could also load in each individual
37 certificate for every client if you wanted to be really strict about it.
38
39 {% highlight bash %}
40 # keytool -import -alias "My CA" -file /var/lib/puppet/ssl/ca/ca_crt.pem -keystore truststore.jks
41 Enter keystore password:
42 Re-enter new password:
43 .
44 .
45 .
46 Trust this certificate? [no]:  y
47 Certificate was added to keystore
48 {% endhighlight %}
49
50 You can view your certificate:
51
52 {% highlight bash %}
53 # keytool -list -keystore truststore.jks
54 Enter keystore password:
55
56 Keystore type: JKS
57 Keystore provider: SUN
58
59 Your keystore contains 1 entry
60
61 my ca, Mar 30, 2012, trustedCertEntry,
62 Certificate fingerprint (MD5): 99:D3:28:6B:37:13:7A:A2:B8:73:75:4A:31:78:0B:68
63 {% endhighlight %}
64
65 Note the MD5 fingerprint, you can verify this is the one from your CA:
66
67 {% highlight bash %}
68 # openssl x509 -in /var/lib/puppet/ssl/ca/ca_crt.pem -fingerprint -md5
69 MD5 Fingerprint=99:D3:28:6B:37:13:7A:A2:B8:73:75:4A:31:78:0B:68
70 {% endhighlight %}
71
72 Now we create the certificate for our ActiveMQ machine and store that in the key store
73
74 {% highlight bash %}
75 # puppet cert generate stomp.my.net
76 notice: stomp.my.net has a waiting certificate request
77 notice: Signed certificate request for stomp.my.net
78 notice: Removing file Puppet::SSL::CertificateRequest stomp.my.net at '/var/lib/puppet/ssl/ca/requests/stomp.my.net.pem'
79 notice: Removing file Puppet::SSL::CertificateRequest stomp.my.net at '/var/lib/puppet/ssl/certificate_requests/stomp.my.net.pem'
80 {% endhighlight %}
81
82 And then we convert it into a format keytool can understand and import it:
83
84 {% highlight bash %}
85 # cat /var/lib/puppet/ssl/private_keys/stomp.my.net.pem /var/lib/puppet/ssl/certs/stomp.my.net.pem > temp.pem
86 # openssl pkcs12 -export -in temp.pem -out activemq.p12 -name stomp.my.net
87 Enter Export Password:
88 Verifying - Enter Export Password:
89 # keytool -importkeystore  -destkeystore keystore.jks -srckeystore activemq.p12 -srcstoretype PKCS12 -alias stomp.my.net
90 Enter destination keystore password:
91 Re-enter new password:
92 Enter source keystore password:
93 {% endhighlight %}
94
95 You can validate this was correct:
96
97 {% highlight bash %}
98 # keytool -list -keystore keystore.jks
99 Enter keystore password:
100
101 Keystore type: JKS
102 Keystore provider: SUN
103
104 Your keystore contains 1 entry
105
106 stomp.my.net, Mar 30, 2012, PrivateKeyEntry,
107 Certificate fingerprint (MD5): 7E:2A:B4:4D:1E:6D:D1:70:A9:E7:20:0D:9D:41:F3:B9
108
109 # puppet cert fingerprint stomp.my.net --digest=md5
110 MD5 Fingerprint=7E:2A:B4:4D:1E:6D:D1:70:A9:E7:20:0D:9D:41:F3:B9
111 {% endhighlight %}
112
113 ### Configure ActiveMQ
114 We need to tell ActiveMQ to read the stores we made:
115
116 {% highlight xml %}
117 <sslContext>
118    <sslContext
119         keyStore="keystore.jks" keyStorePassword="secret"
120         trustStore="truststore.jks" trustStorePassword="secret"
121    />
122 </sslContext>
123 {% endhighlight %}
124
125 And we need to tell ActiveMQ to only accept fully verified connections:
126
127 {% highlight xml %}
128 <transportConnectors>
129     <transportConnector name="openwire" uri="tcp://0.0.0.0:6166"/>
130     <transportConnector name="stompssl" uri="stomp+ssl://0.0.0.0:6164?needClientAuth=true"/>
131 </transportConnectors>
132 {% endhighlight %}
133
134 If you were to attempt to connect a mcollectived or client using the anonymous setup
135 detailed above that should fail as we have not yet setup credentials for the mcollectived
136 or mcollective client to use.
137
138 ### Setting up mcollectived
139
140 For the MCollective daemon you can use your existing Puppet certificates by editing the _server.cfg_
141
142 {% highlight ini %}
143 connector = activemq
144 plugin.activemq.base64 = yes
145 plugin.activemq.pool.size = 2
146 plugin.activemq.pool.1.host = stomp.my.net
147 plugin.activemq.pool.1.port = 6164
148 plugin.activemq.pool.1.user = mcollective
149 plugin.activemq.pool.1.password = secret
150 plugin.activemq.pool.1.ssl = 1
151 plugin.activemq.pool.1.ssl.ca = /var/lib/puppet/ssl/ca/ca_crt.pem
152 plugin.activemq.pool.1.ssl.key = /var/lib/puppet/ssl/private_keys/fqdn.pem
153 plugin.activemq.pool.1.ssl.cert = /var/lib/puppet/ssl/certs/fqdn.pem
154 {% endhighlight %}
155
156 Fix the paths to the private key and certificate, they will be named after your machines FQDN.
157
158 ### Setting up mcollective clients
159
160 Each client will now need a TLS certificate issued by the Puppet CA in order to be able to
161 connect to the ActiveMQ:
162
163 {% highlight bash %}
164 # puppet cert generate ripienaar
165 notice: ripienaar has a waiting certificate request
166 notice: Signed certificate request for ripienaar
167 notice: Removing file Puppet::SSL::CertificateRequest ripienaar at '/var/lib/puppet/ssl/ca/requests/ripienaar.pem'
168 notice: Removing file Puppet::SSL::CertificateRequest ripienaar at '/var/lib/puppet/ssl/certificate_requests/ripienaar.pem'
169 {% endhighlight %}
170
171 Copy the certificates to your user:
172
173 {% highlight bash %}
174 # mkdir /home/rip/.mcollective.d
175 # cp /var/lib/puppet/ssl/ca/ca_crt.pem /home/rip/.mcollective.d/
176 # cp /var/lib/puppet/ssl/private_keys/ripienaar.pem /home/rip/.mcollective.d/ripienaar-private.pem
177 # cp /var/lib/puppet/ssl/public_keys/ripienaar.pem /home/rip/.mcollective.d/ripienaar.pem
178 # cp /var/lib/puppet/ssl/certs/ripienaar.pem /home/rip/.mcollective.d/ripienaar-cert.pem
179 # chown -R rip:rip /home/rip/.mcollective.d
180 {% endhighlight %}
181
182 You can now configure the mcollective client config in _/home/rip/.mcollective_ to use these:
183
184 {% highlight ini %}
185 connector = activemq
186 plugin.activemq.base64 = yes
187 plugin.activemq.pool.size = 2
188 plugin.activemq.pool.1.host = stomp.my.net
189 plugin.activemq.pool.1.port = 6164
190 plugin.activemq.pool.1.user = ripienaar
191 plugin.activemq.pool.1.password = secret
192 plugin.activemq.pool.1.ssl = 1
193 plugin.activemq.pool.1.ssl.ca = /home/rip/.mcollective.d/ca_crt.pem
194 plugin.activemq.pool.1.ssl.key = /home/rip/.mcollective.d/ripienaar-private.pem
195 plugin.activemq.pool.1.ssl.cert = /home/rip/.mcollective.d/ripienaar-cert.pem
196 {% endhighlight %}
197
198 If you are using the SSL or AES security plugins you can use these same files using the _/home/rip/.mcollective.d/ripienaar.pem_
199 as the public key for those plugins.
200
201 ### Common Errors
202
203 You will get some obvious errors from this code if any files are missing, but the errors fro SSL validation will be pretty
204 hard to understand.
205
206 There are only 2 scenarios here:
207
208 #### ActiveMQ rejects the client
209 When the client connects using a CA set in _plugin.activemq.pool.1.ssl.ca_ that does not match the one
210 in the ActiveMQ _truststore.jks_:
211
212 {% highlight console %}
213 failed: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
214 {% endhighlight %}
215
216 And in the ActiveMQ log:
217
218 {% highlight console %}
219 Transport failed: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
220 {% endhighlight %}
221
222 When your client has the correct CA but his certificates are not signed by that CA:
223
224 {% highlight console %}
225 failed: SSL_connect returned=1 errno=0 state=SSLv3 read finished A: sslv3 alert certificate unknown
226 {% endhighlight %}
227
228 And in the ActiveMQ log:
229
230 {% highlight console %}
231 sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
232 {% endhighlight %}
233
234 ## Basic anonymous TLS between Stomp and ActiveMQ
235 ### Create a keystore with existing certs
236 If you have an exiting PKI deployment, you can probably reuse Puppet ones too the main
237 point is that you already have a key and signed cert signed by some CA and you
238 now want to create a Java Keystore follow these steps:
239
240 {% highlight bash %}
241 # cat /etc/pki/host.key /etc/pki/ca.pem /etc/pki/host.cert >cert.pem
242 # openssl pkcs12 -export -in cert.pem -out activemq.p12 -name `hostname`
243 # keytool -importkeystore -deststorepass secret -destkeypass secret -destkeystore keystore.jks -srckeystore activemq.p12 -srcstoretype PKCS12 -alias `hostname`
244 {% endhighlight %}
245
246 The above steps will create a standard Java keystore in _keystore.jks_ which you
247 should store in your ActiveMQ config directory.  It will have a password
248 _secret_ you should change this.
249
250 ### Configure ActiveMQ
251
252 To let ActiveMQ load your keystore you should add the following to the
253 _activemq.xml_ file:
254
255 {% highlight xml %}
256 <sslContext>
257    <sslContext keyStore="keystore.jks" keyStorePassword="secret" />
258 </sslContext>
259 {% endhighlight %}
260
261 And you should add a SSL stomp listener, you should get port 6164 opened:
262
263 {% highlight xml %}
264 <transportConnectors>
265     <transportConnector name="openwire" uri="tcp://0.0.0.0:6166"/>
266     <transportConnector name="stomp" uri="stomp://0.0.0.0:6163"/>
267     <transportConnector name="stompssl" uri="stomp+ssl://0.0.0.0:6164"/>
268 </transportConnectors>
269 {% endhighlight %}
270
271 ### Configure MCollective
272
273 The last step is to tell MCollective to use the SSL connection, to do this you
274 need to use the new pool based configuration, even if you just have 1 ActiveMQ
275 in your pool:
276
277 {% highlight ini %}
278 plugin.stomp.pool.size = 1
279 plugin.stomp.pool.host1 = stomp.your.com
280 plugin.stomp.pool.port1 = 6164
281 plugin.stomp.pool.user1 = mcollective
282 plugin.stomp.pool.password1 = secret
283 plugin.stomp.pool.ssl1 = true
284 {% endhighlight %}
285
286 You should now verify with tcpdump or wireshark that the connection and traffic
287 really is all encrypted.