我正在尝试使用SSL在Tomcat 7.0.23下运行JMX。 服务器位于AWS,这意味着所有主机都是NAT,我需要使用JmxRemoteLifecycleListener来显式设置JMX使用的两个端口。 我已经在这个主题上做了大量的阅读,但是我不能让所有的部分一起正常工作。
我可以让JMX在没有SSL的情况下正常工作。 我已经为我的Tomcat版本下载了catalina-jmx-remote.jar的版本,并将其安装在我的tomcat / lib目录中。 我的server.xml包含:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="1099" rmiServerPortPlatform="1098" />
当我用以下设置启动Tomcat时,我可以连接一个不安全的会话:
-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
但是,如果我改变这些以下,那么我无法build立一个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仅包含通过以下方式创build的单个证书:
openssl x509 -outform der -in cert.pem -out cert.der keytool -import -alias tomcat -keystore keystore.dat -file cert.der -storepass <password>
truststore.dat包含java cacerts的完整副本以及我自签名证书的CA证书:
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>
启动Tomcat后,我尝试通过jconsole连接,但无法build立连接。 我尝试使用opensslvalidationSSL,但看起来像Tomcat没有使用证书:
$ 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 ---
我已经validation我的本地密钥库和信任库是通过导出密钥并validation证书链来正确设置的(combined.pem是来自truststore.dat的所有CA证书,cert.pem是来自keystore.dat的证书):
$ openssl verify -verbose -purpose sslserver -CAfile combined.pem cert.pem cert.pem: OK
所以现在我完全失去了。 证书和CA证书看起来是正确的。 未encryption的JMX连接正常工作。 但我似乎无法获得使用SSL的连接。 我在这里错过了什么?
我不知道这是不是只是一个红鲱鱼,但我没有看到任何方式来指定什么证书的密钥库被JMX使用。 我读的一些内容暗示它只是使用别名“tomcat”的证书。 那是对的吗?
我花了一段时间才弄清楚,但我终于明白了。 关键是在创build自签名证书时如何设置密钥库和信任库文件。 下面是我写的一个bash脚本,使其易于记忆:
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