![]() |
Contents | Next![]() |
Chapter 2
Monitoring and Management Using JMX TechnologyThe Java virtual machine (Java VM ) has built-in instrumentation that enables you to monitor and manage it using the Java Management Extensions (JMX) technology. These built-in management utilities are often referred to as out-of-the-box management tools for the Java VM. You can also monitor any appropriately instrumented applications using the JMX API. Setting System PropertiesTo enable and configure the out-of-the-box JMX agent so that it can monitor and manage the Java VM, you must set certain system properties when you start the Java VM. You set a system property on the command-line as follows. java -Dproperty=value ... You can set any number of system properties in this way. If you do not specify a value for a management property, then the property is set with its default value. The full set of out-of-the-box management properties is described in Table 2-1 at the end of this chapter. You can also set system properties in a configuration file, as described in Out-of-the-Box Monitoring and Management Properties. Note - To run the Java VM from the command line, you must add JRE_HOME/bin to your path, where JRE_HOME is the directory containing the Java Runtime Environment (JRE) implementation. Alternatively, you can enter the full path when you type the command. The following documents describe the syntax and the full set of command-line options supported by the Java HotSpot VMs. Enabling the Out-of-the-Box ManagementTo monitor a Java platform using the JMX API, you must do the following.
These steps are described in the next sections. Local Monitoring and ManagementUnder previous releases of the Java SE platform, to allow the JMX client access to a local Java VM, you had to set the following system property when you started the Java VM or Java application. com.sun.management.jmxremote Setting this property registered the Java VM platform's MBeans and published the Remote Method Invocation (RMI) connector via a private interface to allow JMX client applications to monitor a local Java platform, that is, a Java VM running on the same machine as the JMX client. In the Java SE 6 platform, it is no longer necessary to set this system property. Any application that is started on the Java SE 6 platform will support the Attach API, and so will automatically be made available for local monitoring and management when needed. For example, previously, to enable the JMX agent for the Java SE sample application Notepad, you would have to run the following commands. % cd JDK_HOME/demo/jfc/Notepad % java -Dcom.sun.management.jmxremote -jar Notepad.jar In the above command, JDK_HOME is the directory in which the Java Development Kit (JDK) is installed. In the Java SE 6 platform, you would simply have to run the following command to start Notepad. % java -jar Notepad.jar Once Notepad has been started, a JMX client using the Attach API can then enable the out-of-the-box management agent to monitor and manage the Notepad application. Note - On Windows platforms, for security reasons, local monitoring and management is only supported if your default temporary directory is on a file system that allows the setting of permissions on files and directories (for example, on a New Technology File System (NTFS) file system). It is not supported on a File Allocation Table (FAT) file system, which provides insufficient access controls. Local Monitoring and Management Using JConsoleLocal monitoring with JConsole is useful for development and creating prototypes. Using JConsole locally is not recommended for production environments, because JConsole itself consumes significant system resources. Rather, you should use JConsole on a remote system to isolate it from the platform being monitored. However, if you do wish to perform local monitoring using JConsole, you start the tool by typing jconsole in a command shell. When you start jconsole without any arguments, it will automatically detect all local Java applications, and display a dialog box that enables you to select the application you want to monitor. Both JConsole and the application must by executed by the same user, since the monitoring and management system uses the operating system's file permissions. Note - To run JConsole from the command line, you must add JDK_HOME/bin to your path. Alternatively, you can enter the full path when you type the command. For more information, see Chapter 3, Using JConsole. Remote Monitoring and ManagementTo enable monitoring and management from remote systems, you must set the following system property when you start the Java VM. com.sun.management.jmxremote.port=portNum In the property above, portNum is the port number through which you want to enable JMX RMI connections. Be sure to specify an unused port number. In addition to publishing an RMI connector for local access, setting this property publishes an additional RMI connector in a private read-only registry at the specified port using a well known name, "jmxrmi". Note - You must set the above system property in addition to any properties you might set for security. Remote monitoring and management requires security, to ensure that unauthorized persons cannot control or monitor your application. Password authentication over the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) is enabled by default. You can disable password authentication and SSL separately, as described in the next sections. For production systems, use SSL client certificates for authentication instead of passwords, or ensure that the client obtains the remote connector object securely, for example through a secure LDAP server or a file in a shared secure file system. See the topics Using SSL and Using LDAP Authentication for more information. The Java platform supports pluggable login modules for authentication. You can plug in any login module depending on the authentication infrastructure in your organization. The section titled Using LDAP Authentication describes how to plug in the com.sun.security.auth.module.LdapLoginModule for Lightweight Directory Access Protocol (LDAP) based authentication. After you have enabled the JMX agent for remote use, you can monitor your application using JConsole, as described in Remote Monitoring with JConsole. How to connect to the management agent programmatically is described in Connecting to the JMX Agent Programmatically. Using Password AuthenticationUsing LDAP AuthenticationThe JMXAuthenticator
implementation in the JMX agent is based on Java Authentication and
Authorization Service (JAAS) technology. Authentication is
performed by passing the user credentials to a JAAS javax.security.auth.spi.LoginModule
object. The
com.sun.security.auth.module.LdapLoginModule class enables
authentication using LDAP. You can replace the default
Create a JAAS configuration file that would work in the required
business organization. An example of a configuration file
( ExampleCompanyConfig { com.sun.security.auth.module.LdapLoginModule REQUIRED userProvider="ldap://example-ds/ou=people,dc=examplecompany,dc=com" userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))" authzIdentity=monitorRole; }; The options in the configuration file are briefly explained next. See documentation for the com.sun.security.auth.module.LdapLoginModule class for information about the configuration options shown in the code snippet.
Start your application with the following properties set on the command line:
A sample command line is shown next. java -Dcom.sun.management.jmxremote.port=5000 -Dcom.sun.management.jmxremote.login.config=ExampleCompanyConfig -Djava.security.auth.login.config=ldap.config -jar MyApplication.jar Using File-Based Password AuthenticationThe file-based password authentication mechanism supported by the JMX agent stores the password in clear-text and is intended only for development use. For production use, it is strongly recommended that you use SSL client certificates for authentication or plug in a secure login configuration. Caution - A potential security issue has been identified with password authentication for remote connectors when the client obtains the remote connector from an insecure RMI registry (the default). If an attacker starts a bogus RMI registry on the target server before the legitimate registry is started, then the attacker can steal clients' passwords. This scenario includes the case where you launch a Java VM with remote management enabled, using the system property com.sun.management.jmxremote.port=portNum, even when SSL is enabled. Although such attacks are likely to be noticed, it is nevertheless a vulnerability. By default, when you enable the JMX agent for remote monitoring, it uses password authentication. However, the way you set it up depends on whether you are in a single-user environment or a multiple-user environment. Since passwords are stored in clear-text in the password file, it is not advisable to use your regular user name and password for monitoring. Instead, use the user names specified in the password file such as monitorRole and controlRole. For more information, see Using Password and Access Files.
|
Property | Description | Values |
---|---|---|
com.sun.management.jmxremote |
Enables the JMX remote agent and local monitoring via a JMX connector published on a private interface used by JConsole and any other local JMX clients that use the Attach API. JConsole can use this connector if it is started by the same user as the user that started the agent. No password or access files are checked for requests coming via this connector. |
true / false. Default is true. |
com.sun.management.jmxremote. port |
Enables the JMX remote agent and creates a remote JMX connector to listen through the specified port. By default, the SSL, password, and access file properties are used for this connector. It also enables local monitoring as described for the com.sun.management.jmxremote property. |
Port number. No default. |
com.sun.management.jmxremote. registry.ssl |
Binds the RMI connector stub to an RMI registry protected by SSL. |
true / false. Default is false. |
com.sun.management.jmxremote. ssl |
Enables secure monitoring via SSL. If false, then SSL is not used. |
true / false. Default is true. |
com.sun.management.jmxremote. ssl.enabled.protocols |
A comma-delimited list of SSL/TLS protocol versions to enable. Used in conjunction with com.sun.management.jmxremote.ssl. |
Default SSL/TLS protocol version. |
com.sun.management.jmxremote. ssl.enabled.cipher.suites |
A comma-delimited list of SSL/TLS cipher suites to enable. Used in conjunction with com.sun.management.jmxremote.ssl. |
Default SSL/TLS cipher suites. |
com.sun.management.jmxremote. ssl.need.client.auth |
If this property is true and the property com.sun.management.jmxremote.ssl is also true, then client authentication will be performed. |
true / false. Default is true. |
com.sun.management.jmxremote. authenticate |
If this property is false then JMX does not use passwords or access files: all users are allowed all access. |
true / false. Default is true. |
com.sun.management.jmxremote. password.file |
Specifies location for password file. If com.sun.management.jmxremote.authenticate is false, then this property and the password and access files are ignored. Otherwise, the password file must exist and be in the valid format. If the password file is empty or nonexistent, then no access is allowed. |
JRE_HOME/lib/management/ jmxremote.password |
com.sun.management.jmxremote. access.file |
Specifies location for the access file. If com.sun.management.jmxremote.authenticate is false, then this property and the password and access files are ignored. Otherwise, the access file must exist and be in the valid format. If the access file is empty or nonexistent, then no access is allowed. |
JRE_HOME/lib/management/ jmxremote.access |
Specifies the name of a Java Authentication and Authorization Service (JAAS) login configuration entry to use when the JMX agent authenticates users. When using this property to override the default login configuration, the named configuration entry must be in a file that is loaded by JAAS. In addition, the login modules specified in the configuration should use the name and password callbacks to acquire the user's credentials. For more information, see the API documentation for javax.security.auth.callback.NameCallback and javax.security.auth.callback.PasswordCallback. |
Default login configuration is a file-based password authentication. |
If any errors occur during start up of the MBean server, the RMI registry, or the connector, the Java VM will throw an exception and exit. Configuration errors include the following.
Failure to bind to the port number.
Invalid password file.
Invalid access file.
Password file is readable by users other than the owner.
If your application runs a security manager, then additional permissions are required in the security permissions file.
Once you have enabled the JMX agent, a client can use the following URL to access the monitoring service.
service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi
A client can create a connector for the agent by instantiating a javax.management.remote.JMXServiceURL object using the URL, and then creating a connection using the JMXConnectorFactory.connect method, shown in Example 2-3.
Example 2-3 Creating a Connection Using JMXConnectorFactory.connectMXServiceURL u = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum + "/jmxrmi"); JMXConnector c = JMXConnectorFactory.connect(u);
As stated previously, in the Java SE platform version 6, you can create a JMX client that uses the Attach API to enable out-of-the-box monitoring and management of any applications that are started on the Java SE 6 platform, without having to configure the applications for monitoring when you launch them. The Attach API provides a way for tools to attach to and start agents in the target application. Once an agent is running, JMX clients (and other tools) are able to obtain the JMX connector address for that agent via a property list that is maintained by the Java VM on behalf of the agents. The properties in the list are accessible from tools that use the Attach API. So, if an agent is started in an application, and if the agent creates a property to represent a piece of configuration information, then that configuration information is available to tools that attach to the application.
The JMX agent creates a property with the address of the local JMX connector server. This allows JMX tools to attach to and get the connector address of an agent, if it is running.
Example 2-4 shows code that could be used in a JMX tool to attach to a target VM, get the connector address of the JMX agent and connect to it.
Example 2-4 Attaching a JMX tool to a connector and getting the agent's addressstatic final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; // attach to the target application VirtualMachine vm = VirtualMachine.attach(id); // get the connector address String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); // no connector address, so we start the JMX agent if (connectorAddress == null) { String agent = vm.getSystemProperties().getProperty("java.home") + File.separator + "lib" + File.separator + "management-agent.jar"; vm.loadAgent(agent); // agent is started, get the connector address connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS); } // establish connection to connector server JMXServiceURL url = new JMXServiceURL(connectorAddress); JMXConnector = JMXConnectorFactory.connect(url);
Example 2-4 uses the com.sun.tools.attach.VirtualMachine class's attach() method to attach to a given Java VM so that it can read the properties that the target Java VM maintains on behalf of any agents running in it. If an agent is already running, then the VirtualMachine class's getAgentProperties() method is called to obtain the agent's address. The getAgentProperties() method returns a string property for the local connector address com.sun.management.jmxremote.localConnectorAddress, that you can use to connect to the local JMX agent.
If no agent is running already, then one is loaded by the VirtualMachine from JRE_HOME/lib/management-agent.jar, and its connector address is obtained by getAgentProperties().
A connection to the agent is then established by calling JMXConnectorFactory.connect on a JMX service URL that has been constructed from this connector address.
As explained above, remote access to the out-of-the-box management agent is protected by authentication and authorization, and by SSL encryption, and all configuration is performed by setting system properties or by defining a management.properties file. In most cases, using the out-of-the-box management agent and configuring it through the management.properties file is more than sufficient to provide secure management of remote Java VMs. However, in some cases greater levels of security are required and in other cases certain system configurations do not allow the use of a management.properties file. Such cases might involve exporting the RMI server's remote objects over a certain port to allow passage through a firewall, or exporting the RMI server's remote objects using a specific network interface in multi-homed systems. For such cases, the behavior of the out-of-the-box management agent can be mimicked by using the JMX Remote API directly to create, configure and deploy the management agent programmatically.
This section provides an example of how to implement a JMX agent that identically mimics an out-of-the-box management agent. In exactly the same way as the out-of-the-box management agent, the agent created in Example 2-5 will run on port 3000, will have a password file named password.properties, an access file named access.properties and it will implement the default configuration for SSL/TLS-based RMI Socket Factories, requiring server authentication only. This example assumes a keystore has already been created, as described in Using SSL. Information about how to set up the SSL configuration can be found in the JSSE Reference Guide.
To enable monitoring and management on an application named com.example.MyApp using the out-of-the-box JMX agent with the configuration described above, you would run com.example.MyApp with the following command.
% java -Dcom.sun.management.jmxremote.port=3000 \ -Dcom.sun.management.jmxremote.password.file=password.properties \ -Dcom.sun.management.jmxremote.access.file=access.properties \ -Djavax.net.ssl.keyStore=keystore \ -Djavax.net.ssl.keyStorePassword=password \ com.example.MyApp
Note - The com.sun.management.jmxremote.* properties could have been specified in a management.properties file instead of passing them at the command line. In that case, the system property -Dcom.sun.management.config.file=management.properties would be required to specify the location of the management.properties file.
Example 2-5 shows the code you would need to write to create programmatically a JMX agent that will allow exactly the same monitoring and management on com.example.MyApp as would be possible using the command above.
Example 2-5 Mimicking an Out-of-the-Box JMX Agent Programmaticallypackage com.example; import java.lang.management.*; import java.rmi.registry.*; import java.util.*; import javax.management.*; import javax.management.remote.*; import javax.management.remote.rmi.*; import javax.rmi.ssl.*; public class MyApp { public static void main(String[] args) throws Exception { // Ensure cryptographically strong random number generator used // to choose the object number - see java.rmi.server.ObjID // System.setProperty("java.rmi.server.randomIDs", "true"); // Start an RMI registry on port 3000. // System.out.println("Create RMI registry on port 3000"); LocateRegistry.createRegistry(3000); // Retrieve the PlatformMBeanServer. // System.out.println("Get the platform's MBean server"); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // Environment map. // System.out.println("Initialize the environment map"); HashMap<String,Object> env = new HashMap<String,Object>(); // Provide SSL-based RMI socket factories. // // The protocol and cipher suites to be enabled will be the ones // defined by the default JSSE implementation and only server // authentication will be required. // SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); // Provide the password file used by the connector server to // perform user authentication. The password file is a properties // based text file specifying username/password pairs. // env.put("jmx.remote.x.password.file", "password.properties"); // Provide the access level file used by the connector server to // perform user authorization. The access level file is a properties // based text file specifying username/access level pairs where // access level is either "readonly" or "readwrite" access to the // MBeanServer operations. // env.put("jmx.remote.x.access.file", "access.properties"); // Create an RMI connector server. // // As specified in the JMXServiceURL the RMIServer stub will be // registered in the RMI registry running in the local host on // port 3000 with the name "jmxrmi". This is the same name the // out-of-the-box management agent uses to register the RMIServer // stub too. // System.out.println("Create an RMI connector server"); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:3000/jmxrmi"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // Start the RMI connector server. // System.out.println("Start the RMI connector server"); cs.start(); } }
Start this application with the following command.
java -Djavax.net.ssl.keyStore=keystore \ -Djavax.net.ssl.keyStorePassword=password \ com.example.MyApp
The com.example.MyApp application will enable the JMX agent and will be able to be monitored and managed in exactly the same way as if the Java platform's out-of-the-box management agent had been used. However, there is one slight but important difference between the RMI registry used by the out-of-the-box management agent and the one used by a management agent that mimics it. The RMI registry used by the out-of-the-box management agent is read-only, namely a single entry can be bound to it and once bound this entry cannot be unbound. This is not true of the RMI registry created in Example 2-5.
Furthermore, both RMI registries are insecure as they do not use SSL/TLS. The RMI registries should be created using SSL/TLS-based RMI socket factories which require client authentication. This will prevent a client from sending its credentials to a rogue RMI server and will also prevent the RMI registry from giving access to the RMI server stub to a non-trusted client.
RMI registries which implement SSL/TLS RMI socket factories can be created by adding the following properties to your management.properties file.
com.sun.management.jmxremote.registry.ssl=true com.sun.management.jmxremote.ssl.need.client.auth=true
Example 2-5 mimics the main behavior of the out-of-the-box JMX agent, but does not replicate all the existing properties in the management.properties file. However, you could add other properties by modifying com.example.MyApp appropriately.
As stated above, the code in Example 2-5 can be used to monitor applications through a firewall, which might not be possible if you use the out-of-the-box monitoring solution. The com.sun.management.jmxremote.port management property specifies the port where the RMI Registry can be reached but the ports where the RMIServer and RMIConnection remote objects are exported is chosen by the RMI stack. To export the remote objects (RMIServer and RMIConnection) to a given port you need to create your own RMI connector server programmatically, as described in Example 2-5. However, you must specify the JMXServiceURL as follows:
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost:" + port1 + "/jndi/rmi://localhost:" + port2 + "/jmxrmi");
In the URL above, port1 is the port number on which the RMIServer and RMIConnection remote objects are exported and port2 is the port number of the RMI Registry.
The Java SE platform provides services that allow Java programming language agents to instrument programs running on the Java VM. Creating an instrumentation agent means you do not have to add any new code to your application in order to allow it to be monitored. Instead of implementing monitoring and management in your application's static main method you implement it in a separate agent class, and start your application with the -javaagent option specified. See the API reference documentation for the java.lang.instrument package for full details about how to create an agent class to instrument your applications.
The following procedure shows how you can adapt the code of com.example.MyApp to make an agent to instrument any other application for monitoring and management.
Create a class called com.example.MyAgent, declaring a premain method rather than a main method.
package com.example; [...] public class MyAgent { public static void premain(String args) throws Exception { [...]
The rest of the code for the com.example.MyAgent class can be exactly the same as the com.example.MyApp class shown in Example 2-5.
An agent is deployed as a Java archive (JAR) file. An attribute in the JAR file manifest specifies the agent class which will be loaded to start the agent. Create a file called MANIFEST.MF, containing the following line.
Premain-Class: com.example.MyAgent
The JAR file should contain the following files.
META-INF/MANIFEST.MF
com/example/MyAgent.class
You can use com.example.MyAgent to instrument any application for monitoring and management. This example uses the Notepad application.
% java -javaagent:MyAgent.jar -Djavax.net.ssl.keyStore=keystore \ -Djavax.net.ssl.keyStorePassword=password -jar Notepad.jar
The com.example.MyAgent agent is specified using the -javaagent option when you start Notepad. Also, if your com.example.MyAgent application replicates the same code as the com.example.MyApp application shown in Example 2-5, then you will need to provide the keystore and password because the RMI connector server is protected by SSL.
![]() |
Contents | Next![]() |