Reputation: 10319
I run Tomcat8 using JDK8 on Centos6. I enable JMX using the following options:
CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9123 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=true"
Unfortunately, when I check what ports are opened I discover that these ports listen to all IP:
netstat -plunt | grep java
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::60555 :::* LISTEN 22752/java
tcp 0 0 ::ffff:127.0.0.1:8080 :::* LISTEN 22752/java
tcp 0 0 :::9123 :::* LISTEN 22752/java
tcp 0 0 :::40867 :::* LISTEN 22752/java
I suppose that if I configure -Dcom.sun.management.jmxremote.local.only=true
all ports should be bind to localhost only (::ffff:127.0.0.1
will appear before all ports).
How to configure JMX to bind to localhost only?
Added
I do not create JMX I use Tomcat JMX: https://tomcat.apache.org/tomcat-8.0-doc/monitoring.html
.
Upvotes: 7
Views: 20898
Reputation: 19235
What you ask for is unnecessary.
com.sun.management.jmxremote.local.only=true
(which by the way is already the default) means it will only accept connections from localhost. It doesn't mean it will only bind to the loopback interface as you assume. Not accepting connections from something not on the local host is just another way of doing it. From sun.management.jmxremote.LocalRMIServerSocketFactory
you can see it is being done like this:
// Walk through the network interfaces to see
// if any of them matches the client's address.
// If true, then the client's address is local.
while (nis.hasMoreElements()) {
NetworkInterface ni = nis.nextElement();
Enumeration<InetAddress> addrs = ni.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress localAddr = addrs.nextElement();
if (localAddr.equals(remoteAddr)) {
return socket;
}
}
}
Why it was done like this rather than binding to loopback, I don't know. But I believe it is just as secure. (or maybe not?)
But if you really want to, then since Java 8u102 and Java 7u131 system property com.sun.management.jmxremote.host
binds the underlying RMI registry to the selected network interface. The value can be any string which is accepted by InetAddress.getByName(String).
Example:
-Dcom.sun.management.jmxremote.host=localhost
see: JDK-6425769 for more information.
Links: Java 8u102 Release Notes
What the docs doesn't mention anywhere is that even when setting com.sun.management.jmxremote.host
you'll still see one JMX port which is bound to all network interfaces. This is because if com.sun.management.jmxremote.local.only=true
then an instance of sun.management.jmxremote.LocalRMIServerSocketFactory
will be started and that one doesn't allow customization, i.e. it doesn't respect com.sun.management.jmxremote.host
property. If that is a bug, an oversight in the JDK-6425769 implementation or intentional, I do not know.
Upvotes: 23
Reputation: 18405
As far as I understand this answer and read Oracle's docs about it, there seems to be no way to configure it without coding. This says in the chapter "Connector server attributes":
When using the default JRMP transport, RMI socket factories can be specified using the attributes
jmx.remote.rmi.client.socket.factory
andjmx.remote.rmi.server.socket.factory
in the environment given to theRMIConnectorServer
constructor. The values of these attributes must be of typeRMIClientSocketFactory
andRMIServerSocketFactory
, respectively. These factories are used when creating the RMI objects associated with the connector.
The only option I see is to implement a custom factory like here and pass the classname to the property along with the JAR/class in classpath.
Correct me if I am wrong.
Upvotes: 4