2008-12-07 27 views
5

Aunque parece que hay alguna documentación sobre cómo exponer JMX a través de varios esquemas de cortafuegos y túneles, en cierto modo quiero lo contrario. Quiero asegurarme de que JMX solo sea accesible para la máquina local. Desafortunadamente, parece que las opciones de administración "listas para usar" no permiten restringir los puertos a una interfaz local y netstat los muestra escuchando en cualquiera/todas las interfaces.Restricción de JMX a localhost

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html#gdevf

Tengo que admitir que estoy desconcertado por las capas de indirección en JMX, el registro RMI, conectores, adaptadores, etc.

me gustaría simplemente encenderlo y luego a través del túnel SSH en lugar de exponerlo al mundo y luego tener que realizar una administración de usuario ardua y superflua y una configuración de seguridad. Sería bueno poder usar un registro RMI integrado y no tener que ejecutar uno externo.

Respuesta

1

No puedo evitar la forma de hacerlo. Incluso después de que los adaptadores jmx comenzaran a venir con el jdk (6 creo?) Seguí usando mx4j para la configuración del adaptador de menor esfuerzo. Es trivial iniciar un adaptador http mx4j en 127.0.0.1 o una interfaz interna solamente. Luego, el SOP debía iniciarse con port forward o usar scripts con comandos wget.

http://mx4j.sourceforge.net/

1

Desafortunadamente actualmente no hay manera de hacerlo.

De acuerdo con la documentación de Sun, una sola dirección -Dcom.sun.management.jmxremote debe abrir solo un puerto local, mientras que -Dcom.sun.management.jmxremote.port = abre un puerto accesible remotamente.

Ambas formas abren un puerto aleatorio adicional al que se puede acceder desde remoto.

He visto -Dcom.sun.management.jmxremote.host =, pero eso no parece tener ningún efecto.

Llegué a la conclusión de que no hay forma y usé un firewall local para proteger el servidor.

2

Una respuesta poco tarde, pero si sigue siendo un problema para usted (o alguien más), creo que esto va a hacer el truco:

import java.io.IOException; 
import java.lang.management.ManagementFactory; 
import java.net.*; 
import java.rmi.registry.LocateRegistry; 
import java.rmi.server.RMISocketFactory; 

import javax.management.MBeanServer; 
import javax.management.remote.*; 

public class LocalJMXPort { 
    public static void main(String[] args) { 
     try { 
      int port = 12468; 
      // Create an instance of our own socket factory (see below) 
      RMISocketFactory factory = new LocalHostSocketFactory(); 

      // Set it as default 
      RMISocketFactory.setSocketFactory(factory); 

      // Create our registry 
      LocateRegistry.createRegistry(port); 

      // Get the MBeanServer and setup a JMXConnectorServer 
      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 
      JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://127.0.0.1:"+port+"/jndi/rmi://127.0.0.1:"+port+"/jmxrmi"); 
      JMXConnectorServer rmiServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); 
      rmiServer.start(); 

      // Say something 
      System.out.println("Connect your jconsole to localhost:"+port+". Press a key to exit"); 

      // Wait for a key press 
      int in = System.in.read(); 
      //Exit 
      System.out.println("Exiting"); 
      System.exit(0); 
     } catch(Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

    static private class LocalHostSocketFactory extends RMISocketFactory { 
     public ServerSocket createServerSocket(int port) throws IOException { 
      ServerSocket ret = new ServerSocket(); 
      ret.bind(new InetSocketAddress("localhost", port)); 
      return ret; 
     } 

     public Socket createSocket(String host, int port) throws IOException { 
      return new Socket(host, port); 
     } 
    } 
} 

acabo de poner juntos y es posible que lo hice algo realmente estúpido porque mi único objetivo era hacer que fuera vinculante para localhost: port en lugar de *: port y esa parte parece funcionar.

Siéntase libre de comentar si hay cosas que pueden mejorarse o es simplemente estúpido.

3

Si está accediendo desde el host local, entonces es posible hacer lo que JConsole y JVisualVM hacen en este caso, que es usar la API de conexión para encontrar la dirección solo local del servidor (lo que obtiene si ejecuta con -Dcom.sun.management.jmxremote pero no -Dcom.sun.management.jmxremote.port = N) y se conecta a eso. En otra respuesta, Thraidh dice que un puerto accesible remotamente se abre incluso en este caso, lo que era cierto en versiones anteriores, pero no ha sido así en un par de años.

La solución de Fredrik funciona pero es exagerada. Solo necesita definir un RMIServerSocketFactory, no un RMISocketFactory (que define el cliente y el servidor). Esto elimina la necesidad de configurar el cliente especialmente. El código en http://vafer.org/blog/20061010091658 me parece correcto.

La administración "lista para usar" construida con propiedades de línea de comandos como -Dcom.sun.management.jmxremote solo puede llevarlo hasta el momento antes de que necesite comenzar a programar con la API JMX. Por lo general, hemos sido reacios a que la administración lista para usar se convierta en una API paralela completa, por lo que hay problemas como este que están fuera de su alcance. Explicamos cómo ir de uno a otro here.

Éamonn McManus, JMX Spec Lead