Friday, September 2, 2011

SSL enabled JConsole to monitor a WSO2 Carbon Server Securely

WSO2 Products like WSO2 AS, ESB, BPS etc. are MBeans enabled servers such that they can be monitored via JMX clients. JConsole is a graphical JMX monitoring client which comes as a part of JDK.
Recently I had to securely monitor a remote WSO2 carbon server.
But the problem is, now any remote user can implement a MBean on the target server and use System.exit() from the client end to kill the Carbon server. So we need to harden  (or secure and restrict) the communication between client and server.
So I used jConsole via a SSL tunnel which enforces client authentication and RMI-registry authentication. Here’re the steps I took to solve the problem.
Note - Feel free to shout back in case you need more clarifications. In some steps I assumed the audience is aware of JMX, public key cryptography etc.

Content




Applied for
  • Carbon 3.2.0 (or above) based products (WSO2 BPS 2.1.0, WSO2 AS 4.1.0, WSO2 ESB 4.0.0 etc)
  • Sun JDK 1.6.0_24


Enable remote JMX monitoring for Carbon 
    Once you start a WSO2 Carbon instance, default JMX Server is started as bound to localhost.
    Refer the Carbon console log.
    INFO - JMXServerManager - JMX Service URL : service:jmx:rmi://localhost:11111/jndi/rmi://localhost:9999/jmxrmi

    You can modify these ports at $CARBON_HOME/repository/conf/carbon.xml. See
    <Ports>
            <!-- The JMX Ports -->
            <JMX>
                <!--The port RMI registry is exposed-->
                <RMIRegistryPort>9999</RMIRegistryPort>
                <!--The port RMI server should be exposed-->
                <RMIServerPort>11111</RMIServerPort>
            </JMX>
    </Ports>

    But to enable remote access, the JMX server should be unbound from localhost and bound to a remotely accessible IP address. This can be done by modifying $CARBON_HOME/repository/conf/advanced/jmx.xml. Modify the to the preferred IP address.
    <JMX xmlns="http://wso2.org/projects/carbon/jmx.xml">
        <StartRMIServer>true</StartRMIServer>
        <!-- HostName, or Network interface to which this RMI server should be bound -->
        <HostName>localhost</HostName>
        <!-- ${Ports.JMX.RMIRegistryPort} is defined in the Ports section of the carbon.xml-->
        <RMIRegistryPort>${Ports.JMX.RMIRegistryPort}</RMIRegistryPort>
        <!-- ${Ports.JMX.RMIRegistryPort} is defined in the Ports section of the carbon.xml-->
        <RMIServerPort>${Ports.JMX.RMIServerPort}</RMIServerPort>
    </JMX>

    Once the server is restarted, any external user can remotely monitor the Carbon instance via the exposed ports.
    See the console log to make sure, whether the modifications were applied correctly.
    INFO - JMXServerManager - JMX Service URL : service:jmx:rmi://192.254.45.65:11111/jndi/rmi://192.254.45.65:9999/jmxrmi

    Now the problem is using this exposed URL, a remote user can implement a MBean on the target server and use System.exit() from the client end to kill the Carbon instance. So we need to harden  (or secure and restrict ) the communication between client and server.

    Enforcing SSL
    Next step is to adding SSL to the communication.
    First of all we need to create a certificate which is used to encrypt the communication between JMX client and JMX server. For the simplicity we can use the keytool shipped with JDK to generate a self-signed certificate which will be used by the Carbon instance.
    Note - For more information on keytool referhttp://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html

    Use the following command to generate the certificate.
    Note - you can prefer any place to keep the certificates. In as Carbon developers we use this location to store as a best-practice.
    keytool -genkey -alias jconsole -keystore $CARBON_HOME/repository/resources/security/.jConsoleKeyStore

    During this operation, a public and private key pair and a certificate which is signed by the private key is generated.

    Now we need to export this self-signed certificate which is used by the JMX server and import it into trust store of our JMX client. In our case it’s jConsole. To do that use the following steps.
    1. Export the certificate to file called jConsole.cert
      keytool -export -alias jconsole -keystore $CARBON_HOME/repository/resources/security/.jConsoleKeyStore -file jconsole.cert
    2. Securely transfer jconsole.cert to the machine where the JMX client is installed
    3. Import the jconsole.cert to a truststore used by jConsole using the following command
      keytool -import -alias carbon -keystore JAVA_HOME/bin/.jconsoleTrustStore -file jconsole.cert

    Now all the configurations are set for enforce SSL communication. Now the Carbon instance and jConsole need to be restarted with relavant JVM options.
    • Use the following command to start the Carbon instance with the mentioned JVM options.
      Note - Here the keystore password is what is specified while generating the self-signed certificate for Carbon instance.
      $CARBON_HOME/bin/wso2server.sh
      -Dcom.sun.management.jmxremote.ssl=true
      -Djavax.net.ssl.keyStore=$CARBON_HOME/repository/resources/security/.jConsoleKeyStore -Djavax.net.ssl.keyStorePassword=secret
    • To start jConsole
      jconsole -J-Djavax.net.ssl.trustStore=JAVA_HOME/bin/.jconsoleTrustStore

    Now the next step is to enforce SSL client authentication.

    Enforcing SSL client authentication

    To enable SSL client authentication, what we have to do is same as enforcing SSL communication.
    All we have to do is generate the self-signed certificate for jConsole and export that certificate and import it back to a trust store used by the Carbon instance.

    Use the following command to generate the certificate.
    keytool -genkey -alias jconsole_client -keystore JAVA_HOME/bin/.jconsoleKeyStore

    Now Export the certificate to file called jconsole_client.cert.

    Then securely transfer jconsole_client.cert to where the Carbon instance is running.

    Now import jconsole_client.cert to the trust store used by Carbon instance using the following command.
    keytool -import -alias jconsole_client -keystore $CARBON_HOME/repository/resources/security/.jConsoleTrustStore -file jconsole_client.cert

    Now all the configurations are set for enforce SSL communication and SSL client authentication. Now the Carbon instance and jConsole need to be restarted with relavant JVM options.
    • Use the following command to start the Carbon instance with the mentioned JVM options.
      Note - Here the keystore password is what is specified while generating the self-signed certificate for Carbon instance.
      $CARBON_HOME/bin/wso2server.sh
      -Dcom.sun.management.jmxremote.ssl=true
      -Djavax.net.ssl.keyStore=$CARBON_HOME/repository/resources/security/.jConsoleKeyStore -Djavax.net.ssl.keyStorePassword=secret
      -Dcom.sun.management.jmxremote.ssl.need.client.auth=true
      -Djavax.net.ssl.trustStore=$CARBON_HOME/repository/resources/security/.jConsoleTrustStore
    • To start jConsole use the following command
      jconsole -J-Djavax.net.ssl.keyStore=JAVA_HOME/bin/.jconsoleKeyStore -J-Djavax.net.ssl.keyStorePassword=secret -J-Djavax.net.ssl.trustStore=JAVA_HOME/bin/.jconsoleTrustStore

    Enforcing RMI-registry authentication

    Now RMI-registry which is remotely accessible from a separate port (in the above description it’s 9999) also need to be enforced with SSL client authentication. As we have all configured the trust stores and keystores in both client and server end, only requirement to enable RMI-registry authentication is to add the following JVM option to the WSO2 Carbon instance starting script.
    -Dcom.sun.management.jmxremote.registry.ssl=true

    eg - 
    $CARBON_HOME/bin/wso2server.sh
    -Dcom.sun.management.jmxremote.ssl=true
    -Djavax.net.ssl.keyStore=$CARBON_HOME/repository/resources/security/.jConsoleKeyStore -Djavax.net.ssl.keyStorePassword=secret
    -Dcom.sun.management.jmxremote.ssl.need.client.auth=true
    -Djavax.net.ssl.trustStore=$CARBON_HOME/repository/resources/security/.jConsoleTrustStore
    -Dcom.sun.management.jmxremote.registry.ssl=true

    No comments:

    Post a Comment