Obtendo o JMX trabalhando no Tomcat 7 com SSL e um certificado autoassinado

1

Estou tentando fazer com que o JMX funcione com o Tomcat 7.0.23 com SSL. Os servidores estão localizados no AWS, o que significa que todos os hosts são NAT, e eu preciso usar o JmxRemoteLifecycleListener para definir explicitamente as duas portas usadas pelo JMX. Eu tenho lido muito sobre o assunto, mas não consigo fazer todas as partes trabalharem juntas corretamente.

Eu posso fazer o JMX funcionar sem o SSL. Eu baixei a versão do catalina-jmx-remote.jar para minha versão do Tomcat e instalei no meu diretório tomcat / lib. Meu server.xml contém:

  <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" 
        rmiRegistryPortPlatform="1099" rmiServerPortPlatform="1098" />

Quando eu inicio o Tomcat com as seguintes configurações, posso me conectar a uma sessão insegura:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password 
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access 
-Djava.rmi.server.hostname=<public IP of server> 
-Dcom.sun.management.jmxremote.ssl=false

No entanto, se eu alterar esses itens para o seguinte, não será possível estabelecer uma conexão SSL:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password 
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access 
-Djava.rmi.server.hostname=<public IP of server> 
-Dcom.sun.management.jmxremote.ssl=true
-Dcom.sun.management.jmxremote.registry.ssl=true
-Dcom.sun.management.jmxremote.ssl.need.client.auth=false 
-Dcom.sun.management.jmxremote.authenticate=true
-Djavax.net.ssl.keyStore=/path/to/keystore.dat 
-Djavax.net.ssl.keyStorePassword=<password>
-Djavax.net.ssl.trustStore=/path/to/truststore.dat 
-Djavax.net.ssl.trustStorePassword=<password>

keystore.dat contém apenas um único certificado criado por:

openssl x509 -outform der -in cert.pem -out cert.der
keytool -import -alias tomcat -keystore keystore.dat -file cert.der -storepass <password>

truststore.dat contém uma cópia completa dos java cacerts mais o certificado CA para meu certificado autoassinado:

cp $JAVA_HOME/jre/lib/security/cacerts truststore.dat
keytool -storepasswd -storepass changeit -new <password> -keystore truststore.dat
keytool -import -trustcacerts -file mycacert.pem -alias myalias -keystore truststore.dat -storepass <password>

Após o lançamento do Tomcat, tentei conectar-me através do jconsole, mas não consigo estabelecer uma conexão. Eu tentei verificar o SSL usando o openssl, mas parece que o Tomcat não está fazendo uso do certificado:

$ openssl s_client -connect <host>:1099
CONNECTED(00000003)
140735160957372:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 322 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

Eu verifiquei que meu keystore e truststore locais estão configurados corretamente exportando as chaves e verificando a cadeia de certificados (combined.pem é todos os certificados de CA de truststore.dat e cert.pem é meu certificado de keystore.dat ):

$ openssl verify -verbose -purpose sslserver -CAfile combined.pem cert.pem
cert.pem: OK

Então, agora estou em uma perda completa. O certificado e o certificado CA parecem corretos. Conexões JMX não criptografadas funcionam. Mas não consigo obter a conexão para usar SSL. O que estou perdendo aqui?

Não sei se isso é apenas um arenque vermelho ou não, mas não vejo como especificar qual certificado no keyStore é usado pelo JMX. Alguns dos que eu li implicam que apenas usa um certificado com o alias "tomcat". Isso está correto?

    
por Bruce P 30.09.2013 / 21:48

1 resposta

0

Demorei um pouco para descobrir isso, mas finalmente consegui. A chave é como o keystore & Os arquivos truststore são configurados ao criar certificados autoassinados. Aqui está um script que eu escrevi para tornar mais fácil lembrar:

DNAME="CN=foo JMX, OU=prodops, O=foo.com, L=Somewhere, S=XX, C=US"
DAYS=3650
PASSWORD=<password>
CACERTS="/path/to/java/jre/lib/security/cacerts"

rm -f jconsole* tomcat*

# First, create the keystore and truststore for the application, tomcat in this case.  Use $CACERTS as the basis for the new keystore & truststore so that all public CA's remain intact:

keytool -genkey -alias tomcat -keyalg RSA -validity ${DAYS} -keystore tomcat.keystore -storepass ${PASSWORD} -keypass ${PASSWORD} -dname "${DNAME}"
cp ${CACERTS} tomcat.truststore
keytool -storepasswd -keystore tomcat.truststore -storepass changeit -new ${PASSWORD}
keytool -genkey -alias tomcat -keyalg RSA -validity ${DAYS} -keystore tomcat.truststore -storepass ${PASSWORD} -keypass ${PASSWORD} -dname "${DNAME}"

# And do the same for the JMX client, jconsole in this case:

keytool -genkey -alias jconsole -keyalg RSA -validity ${DAYS} -keystore jconsole.keystore -storepass ${PASSWORD} -keypass ${PASSWORD} -dname "${DNAME}"
cp ${CACERTS} jconsole.truststore
keytool -storepasswd -keystore jconsole.truststore -storepass changeit -new ${PASSWORD}
keytool -genkey -alias jconsole -keyalg RSA -validity ${DAYS} -keystore jconsole.truststore -storepass ${PASSWORD} -keypass ${PASSWORD} -dname "${DNAME}"

# Then, export the public certificates from the keystores:

keytool -export -alias tomcat -keystore tomcat.keystore -file tomcat.cer -storepass ${PASSWORD}
keytool -export -alias jconsole -keystore jconsole.keystore -file jconsole.cer -storepass ${PASSWORD}

# Finally, import the certificates into the truststores. Again, this allows the application (tomcat) to trust the client (jconsole), and vice-versa:

keytool -import -alias jconsole -file jconsole.cer -keystore tomcat.truststore -storepass ${PASSWORD} -noprompt
keytool -import -alias tomcat -file tomcat.cer -keystore jconsole.truststore -storepass ${PASSWORD} -noprompt

rm -f *.cer
    
por 22.11.2013 / 22:42