Restricting JMX to localhost

后端 未结 4 1783
没有蜡笔的小新
没有蜡笔的小新 2021-02-10 12:49

While there appears to some documentation on how to expose JMX through various firewall and tunneling schemes, I sort of want the opposite. I want to ensure that JMX is only ac

相关标签:
4条回答
  • 2021-02-10 12:53

    Unfortunately there is currently no way to do that.

    According to Sun documentation a sole -Dcom.sun.management.jmxremote should open only a local port while -Dcom.sun.management.jmxremote.port= opens a remotely accessible port.

    Both ways open an additional random port which is accessible from remote.

    I've seen -Dcom.sun.management.jmxremote.host=, but that does not seem to have any effect.

    I came to the conclusion that there is no way and used a local firewall to shield the server.

    0 讨论(0)
  • 2021-02-10 12:56

    If you're accessing from the local host then it is possible to do what JConsole and JVisualVM do in this case, which is to use the Attach API to find the local-only address of the server (what you get if you run with -Dcom.sun.management.jmxremote but not -Dcom.sun.management.jmxremote.port=N) and connect to that. In another answer, Thraidh says that a remotely-accessible port is opened even in this case, which was true in earlier versions but has not been so for a couple of years.

    Fredrik's solution works but is overkill. You only need to define an RMIServerSocketFactory, not an RMISocketFactory (which defines both client and server). This eliminates the need to configure the client specially. The code at http://vafer.org/blog/20061010091658 looks correct to me.

    The "out-of-the-box" management constructed with command-line properties like -Dcom.sun.management.jmxremote can only take you so far before you need to start programming with the JMX API itself. We've generally been reluctant to have the out-of-the-box management evolve into a complete parallel API, which is why there are problems like this one that are out of its reach. We explain how to go from one to the other here.

    Éamonn McManus, JMX Spec Lead

    0 讨论(0)
  • 2021-02-10 13:03

    Can't help with the sun way of doing it. Even after jmx adapters started coming with the jdk (6 i think?) I kept using mx4j for the least-effort adapter setup. It is trivial to start up an mx4j http adapter on 127.0.0.1 or an internal-only interface. Then SOP was to ssh in with port forwards or use scripts with wget commands.

    http://mx4j.sourceforge.net/

    0 讨论(0)
  • 2021-02-10 13:09

    A bit late answer but if it is still a problem for you (or someone else), I think this will do the trick:

    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);
            }
        }
    }
    

    I just put it together and it is possible that I did something really stupid because my only objective was to have it binding to localhost:port instead of *:port and that part seems to work.

    Feel free to comment if there are things that could be bettered or is just plain stupid.

    0 讨论(0)
提交回复
热议问题