将JMX限制为localhost

时间:2008-12-07 00:52:44

标签: security tomcat ssh jmx tunnel

虽然似乎有一些关于如何通过各种防火墙和隧道方案公开JMX的文档,但我有点想要相反。我想确保JMX只能由本地机器访问。不幸的是,似乎“开箱即用”的管理选项不允许将端口限制为本地接口,netstat显示它们在任何/所有接口上进行侦听。

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

我不得不承认我对JMX中的间接层,RMI注册表,连接器,适配器等感到困惑。

我想将其打开,然后通过SSH进行隧道传输,而不是将其暴露给世界,然后必须执行艰巨而多余的用户管理和安全配置。能够使用内置的RMI注册表而不必运行外部注册表会很好。

4 个答案:

答案 0 :(得分:3)

如果您从本地主机访问,则可以执行JConsole和JVisualVM在这种情况下执行的操作,即使用Attach API查找服务器的本地地址(如果您获得的内容)使用-Dcom.sun.management.jmxremote但不是-Dcom.sun.management.jmxremote.port = N)运行并连接到它。在另一个答案中,Thraidh表示,即使在这种情况下,也可以打开一个可远程访问的端口,这在早期版本中是正确的,但在几年内并未如此。

Fredrik的解决方案有效,但有点矫枉过正。您只需要定义RMIServerSocketFactory,而不是RMISocketFactory(定义客户端和服务器)。这消除了专门配置客户端的需要。 http://vafer.org/blog/20061010091658的代码对我来说是正确的。

使用命令行属性(如-Dcom.sun.management.jmxremote)构建的“开箱即用”管理只能在您需要开始使用JMX API本身进行编程之前到目前为止。我们一般不愿意将开箱即用的管理演变成一个完整的并行API,这就是为什么像这样的问题无法实现的原因。我们将解释如何从一个here转到另一个。{/ p>

ÉamonnMcManus,JMX Spec Lead

答案 1 :(得分:2)

有点迟到的答案,但如果它对你(或其他人)来说仍然是一个问题,我认为这样做会有所帮助:

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

我只是把它放在一起,有可能我做了一些非常愚蠢的事情,因为我唯一的目标是让它绑定到localhost:port而不是*:port,这部分似乎有效。

如果有可能更好的事情或者只是简单的愚蠢,请随意评论。

答案 2 :(得分:1)

无法帮助太阳做这件事。即使jmx适配器开始使用jdk(我认为6)?我仍然使用mx4j进行最省力的适配器设置。在127.0.0.1或仅内部接口上启动mx4j http适配器是微不足道的。然后SOP是使用端口转发ssh in或使用带有wget命令的脚本。

http://mx4j.sourceforge.net/

答案 3 :(得分:1)

不幸的是,目前无法做到这一点。

根据Sun文档,唯一的-Dcom.sun.management.jmxremote应该只打开本地端口,而-Dcom.sun.management.jmxremote.port =打开一个可远程访问的端口。

两种方式都可以打开一个可以从远程访问的附加随机端口。

我见过-Dcom.sun.management.jmxremote.host =,但这似乎没有任何效果。

我得出的结论是没有办法使用本地防火墙屏蔽服务器。