X-Git-Url: https://review.fuel-infra.org/gitweb?a=blobdiff_plain;f=website%2Freference%2Fintegration%2Factivemq_ssl.md;fp=website%2Freference%2Fintegration%2Factivemq_ssl.md;h=4e21b72fc7e84285f8178a5f751c53035c77c024;hb=b87d2f4e68281062df1913440ca5753ae63314a9;hp=0000000000000000000000000000000000000000;hpb=ab0ea530b8ac956091f17b104ab2311336cfc250;p=packages%2Fprecise%2Fmcollective.git diff --git a/website/reference/integration/activemq_ssl.md b/website/reference/integration/activemq_ssl.md new file mode 100644 index 0000000..4e21b72 --- /dev/null +++ b/website/reference/integration/activemq_ssl.md @@ -0,0 +1,287 @@ +--- +layout: default +title: ActiveMQ TLS +toc: false +--- +[Security]: http://activemq.apache.org/security.html +[Registration]: /mcollective/reference/plugins/registration.html +[Wildcard]: http://activemq.apache.org/wildcards.html + +In order to achieve end to end encryption we use TLS encryption between +ActiveMQ, the nodes and the client. + +To set this up you need to Java Keystore, the instructions here work for Java +1.6 either Sun or OpenJDK based. + +## Full CA verified TLS between Stomp >= 1.2.2 and ActiveMQ +As of MCollective 2.0.0 and Stomp 1.2.2 it's possible to setup a TLS setup +that will only accept clients with certificates signed by a CA shared with +your clients and your ActiveMQ server like the one provided by Puppet. + +You can only use this setup using the ActiveMQ specific connector plugin, not using +the generic Stomp one. + +These examples will use the Puppet CA to generate the certificates but you can +use any CA as long as you have PEM format keys and certificates. + +### Create ActiveMQ certificates and keystores +With this setup we need the following: + + * A certificate and keys for the ActiveMQ - we will call the ActiveMQ instance stomp.my.net + * A Certificate Authority certificate + * A key store for the ActiveMQ certificates + * A trust store instructing ActiveMQ what connections to trust + +First we create the trust store, we load in our CA file which will instruct ActiveMQ +to trust any certificate signed by the Puppet CA. You could also load in each individual +certificate for every client if you wanted to be really strict about it. + +{% highlight bash %} +# keytool -import -alias "My CA" -file /var/lib/puppet/ssl/ca/ca_crt.pem -keystore truststore.jks +Enter keystore password: +Re-enter new password: +. +. +. +Trust this certificate? [no]: y +Certificate was added to keystore +{% endhighlight %} + +You can view your certificate: + +{% highlight bash %} +# keytool -list -keystore truststore.jks +Enter keystore password: + +Keystore type: JKS +Keystore provider: SUN + +Your keystore contains 1 entry + +my ca, Mar 30, 2012, trustedCertEntry, +Certificate fingerprint (MD5): 99:D3:28:6B:37:13:7A:A2:B8:73:75:4A:31:78:0B:68 +{% endhighlight %} + +Note the MD5 fingerprint, you can verify this is the one from your CA: + +{% highlight bash %} +# openssl x509 -in /var/lib/puppet/ssl/ca/ca_crt.pem -fingerprint -md5 +MD5 Fingerprint=99:D3:28:6B:37:13:7A:A2:B8:73:75:4A:31:78:0B:68 +{% endhighlight %} + +Now we create the certificate for our ActiveMQ machine and store that in the key store + +{% highlight bash %} +# puppet cert generate stomp.my.net +notice: stomp.my.net has a waiting certificate request +notice: Signed certificate request for stomp.my.net +notice: Removing file Puppet::SSL::CertificateRequest stomp.my.net at '/var/lib/puppet/ssl/ca/requests/stomp.my.net.pem' +notice: Removing file Puppet::SSL::CertificateRequest stomp.my.net at '/var/lib/puppet/ssl/certificate_requests/stomp.my.net.pem' +{% endhighlight %} + +And then we convert it into a format keytool can understand and import it: + +{% highlight bash %} +# cat /var/lib/puppet/ssl/private_keys/stomp.my.net.pem /var/lib/puppet/ssl/certs/stomp.my.net.pem > temp.pem +# openssl pkcs12 -export -in temp.pem -out activemq.p12 -name stomp.my.net +Enter Export Password: +Verifying - Enter Export Password: +# keytool -importkeystore -destkeystore keystore.jks -srckeystore activemq.p12 -srcstoretype PKCS12 -alias stomp.my.net +Enter destination keystore password: +Re-enter new password: +Enter source keystore password: +{% endhighlight %} + +You can validate this was correct: + +{% highlight bash %} +# keytool -list -keystore keystore.jks +Enter keystore password: + +Keystore type: JKS +Keystore provider: SUN + +Your keystore contains 1 entry + +stomp.my.net, Mar 30, 2012, PrivateKeyEntry, +Certificate fingerprint (MD5): 7E:2A:B4:4D:1E:6D:D1:70:A9:E7:20:0D:9D:41:F3:B9 + +# puppet cert fingerprint stomp.my.net --digest=md5 +MD5 Fingerprint=7E:2A:B4:4D:1E:6D:D1:70:A9:E7:20:0D:9D:41:F3:B9 +{% endhighlight %} + +### Configure ActiveMQ +We need to tell ActiveMQ to read the stores we made: + +{% highlight xml %} + + + +{% endhighlight %} + +And we need to tell ActiveMQ to only accept fully verified connections: + +{% highlight xml %} + + + + +{% endhighlight %} + +If you were to attempt to connect a mcollectived or client using the anonymous setup +detailed above that should fail as we have not yet setup credentials for the mcollectived +or mcollective client to use. + +### Setting up mcollectived + +For the MCollective daemon you can use your existing Puppet certificates by editing the _server.cfg_ + +{% highlight ini %} +connector = activemq +plugin.activemq.base64 = yes +plugin.activemq.pool.size = 2 +plugin.activemq.pool.1.host = stomp.my.net +plugin.activemq.pool.1.port = 6164 +plugin.activemq.pool.1.user = mcollective +plugin.activemq.pool.1.password = secret +plugin.activemq.pool.1.ssl = 1 +plugin.activemq.pool.1.ssl.ca = /var/lib/puppet/ssl/ca/ca_crt.pem +plugin.activemq.pool.1.ssl.key = /var/lib/puppet/ssl/private_keys/fqdn.pem +plugin.activemq.pool.1.ssl.cert = /var/lib/puppet/ssl/certs/fqdn.pem +{% endhighlight %} + +Fix the paths to the private key and certificate, they will be named after your machines FQDN. + +### Setting up mcollective clients + +Each client will now need a TLS certificate issued by the Puppet CA in order to be able to +connect to the ActiveMQ: + +{% highlight bash %} +# puppet cert generate ripienaar +notice: ripienaar has a waiting certificate request +notice: Signed certificate request for ripienaar +notice: Removing file Puppet::SSL::CertificateRequest ripienaar at '/var/lib/puppet/ssl/ca/requests/ripienaar.pem' +notice: Removing file Puppet::SSL::CertificateRequest ripienaar at '/var/lib/puppet/ssl/certificate_requests/ripienaar.pem' +{% endhighlight %} + +Copy the certificates to your user: + +{% highlight bash %} +# mkdir /home/rip/.mcollective.d +# cp /var/lib/puppet/ssl/ca/ca_crt.pem /home/rip/.mcollective.d/ +# cp /var/lib/puppet/ssl/private_keys/ripienaar.pem /home/rip/.mcollective.d/ripienaar-private.pem +# cp /var/lib/puppet/ssl/public_keys/ripienaar.pem /home/rip/.mcollective.d/ripienaar.pem +# cp /var/lib/puppet/ssl/certs/ripienaar.pem /home/rip/.mcollective.d/ripienaar-cert.pem +# chown -R rip:rip /home/rip/.mcollective.d +{% endhighlight %} + +You can now configure the mcollective client config in _/home/rip/.mcollective_ to use these: + +{% highlight ini %} +connector = activemq +plugin.activemq.base64 = yes +plugin.activemq.pool.size = 2 +plugin.activemq.pool.1.host = stomp.my.net +plugin.activemq.pool.1.port = 6164 +plugin.activemq.pool.1.user = ripienaar +plugin.activemq.pool.1.password = secret +plugin.activemq.pool.1.ssl = 1 +plugin.activemq.pool.1.ssl.ca = /home/rip/.mcollective.d/ca_crt.pem +plugin.activemq.pool.1.ssl.key = /home/rip/.mcollective.d/ripienaar-private.pem +plugin.activemq.pool.1.ssl.cert = /home/rip/.mcollective.d/ripienaar-cert.pem +{% endhighlight %} + +If you are using the SSL or AES security plugins you can use these same files using the _/home/rip/.mcollective.d/ripienaar.pem_ +as the public key for those plugins. + +### Common Errors + +You will get some obvious errors from this code if any files are missing, but the errors fro SSL validation will be pretty +hard to understand. + +There are only 2 scenarios here: + +#### ActiveMQ rejects the client +When the client connects using a CA set in _plugin.activemq.pool.1.ssl.ca_ that does not match the one +in the ActiveMQ _truststore.jks_: + +{% highlight console %} +failed: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed +{% endhighlight %} + +And in the ActiveMQ log: + +{% highlight console %} +Transport failed: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca +{% endhighlight %} + +When your client has the correct CA but his certificates are not signed by that CA: + +{% highlight console %} +failed: SSL_connect returned=1 errno=0 state=SSLv3 read finished A: sslv3 alert certificate unknown +{% endhighlight %} + +And in the ActiveMQ log: + +{% highlight console %} +sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target +{% endhighlight %} + +## Basic anonymous TLS between Stomp and ActiveMQ +### Create a keystore with existing certs +If you have an exiting PKI deployment, you can probably reuse Puppet ones too the main +point is that you already have a key and signed cert signed by some CA and you +now want to create a Java Keystore follow these steps: + +{% highlight bash %} +# cat /etc/pki/host.key /etc/pki/ca.pem /etc/pki/host.cert >cert.pem +# openssl pkcs12 -export -in cert.pem -out activemq.p12 -name `hostname` +# keytool -importkeystore -deststorepass secret -destkeypass secret -destkeystore keystore.jks -srckeystore activemq.p12 -srcstoretype PKCS12 -alias `hostname` +{% endhighlight %} + +The above steps will create a standard Java keystore in _keystore.jks_ which you +should store in your ActiveMQ config directory. It will have a password +_secret_ you should change this. + +### Configure ActiveMQ + +To let ActiveMQ load your keystore you should add the following to the +_activemq.xml_ file: + +{% highlight xml %} + + + +{% endhighlight %} + +And you should add a SSL stomp listener, you should get port 6164 opened: + +{% highlight xml %} + + + + + +{% endhighlight %} + +### Configure MCollective + +The last step is to tell MCollective to use the SSL connection, to do this you +need to use the new pool based configuration, even if you just have 1 ActiveMQ +in your pool: + +{% highlight ini %} +plugin.stomp.pool.size = 1 +plugin.stomp.pool.host1 = stomp.your.com +plugin.stomp.pool.port1 = 6164 +plugin.stomp.pool.user1 = mcollective +plugin.stomp.pool.password1 = secret +plugin.stomp.pool.ssl1 = true +{% endhighlight %} + +You should now verify with tcpdump or wireshark that the connection and traffic +really is all encrypted.