2 Monitoring and Management Using JMX Technology
The 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 Properties
To enable and configure the ready-to-use 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. See Table 2-1 for the full set of ready-to-use management properties. You can also set system properties in a configuration file, as described in the Ready-to-Use Monitoring and Management Properties section.
Note:
To run the Java VM from the command line, you must addJAVA_HOME/bin
to your path, where JAVA_HOME
is the directory where the JDK is installed . Alternatively, you can enter the full path when you enter the command.
The syntax and the full set of command-line options supported by the Java HotSpot VMs are described in the java section of Java Development Kit Tool Specifications.
Ready-to-Use Management
With the current Java SE platform, any application can be monitored and managed locally
when required through the Attach API (no need to specify
-Dcom.sun.management.jmxremote
). However, you need to enable and
configure remote monitoring.
Note:
On Windows platforms, for security reasons, local monitoring and management is supported only 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 JConsole
Local monitoring with JConsole is useful for development. In production environments, be cautious that JConsole itself may affect the platform being monitored.
To perform local monitoring using JConsole, start the tool by entering
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 that you want to monitor. Both JConsole and the application must by executed
by the same user, because the monitoring and management system uses the operating
system's file permissions.
Note:
To run JConsole from the command line, you must addJDK_HOME/bin
to your path.
Alternatively, you can enter the full path when you enter the command. See Using JConsole.
Remote Monitoring and Management
RMI is the transport for remote connection. By default, the remote stubs for locally
created remote objects that are sent to clients contain the IP address of the local host
in dotted-quad
format. For remote stubs to be associated with a
specific interface address, the java.rmi.server.hostname
system
property must be set to IP address of that interface.
To 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
portNum
is the port number to enable JMX RMI connections. Ensure that you 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 the name, jmxrmi
. The port number to which the RMI connector will be bound using the system property: com.sun.management.jmxremote.rmi.port
Ensure to use an unused port number.
Note:
You must set the prior system property in addition to any properties that you might set for security.com.sun.management.jmxremote.local.port
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.
Note:
For production systems, use both SSL client certificates to authenticate the client host and password authentication for user management. See Using SSL and Using LDAP Authentication.The Java platform supports pluggable login modules for authentication. You can plug in any login module depending on the authentication infrastructure in your organization. Using LDAP Authentication describes how to plug in the com.sun.security.auth.module.LdapLoginModule module 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 Authentication
This section details different password authentication methods.
Using File-Based Password Authentication
The 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 recommended that you use SSL client certificates for authentication or plug in a secure login configuration.
Note:
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 start a Java VM with remote management enabled, using the system propertycom.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. As 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
. See Using Password and
Access Files.
Setting Up the Password File
You set up the password file in the JAVA_HOME/conf/management
directory as follows:
- Copy the password template file
jmxremote.password.template
tojmxremote.password
. - Set file permissions so that only the owner can read and write the password file.
- Add passwords for roles such as
monitorRole
andcontrolRole.
If the JDK is used for a single purpose or all invocations need to use the same roles and
passwords for monitoring, editing jmxremote.password
in the
conf/management
directory is appropriate.
If an instance of the JDK is to run with a specific jmxremote.password
file:
- Copy the template to
jmxremote.password
in some other location (not within the JDK directory). - Set file permissions so that only the user starting the Java application can read and write the password file.
- Set the following system property when you start the Java
VM:
com.sun.management.jmxremote.password.file=pwFilePath
Where
pwFilePath
is the path to the password file.
Disabling Password Authentication
Password authentication for remote monitoring is enabled by default. To disable it, set the following system property when you start the Java VM:
com.sun.management.jmxremote.authenticate=false
Note:
Caution : This configuration is insecure. Any remote user who knows (or guesses) your JMX port number and host name will be able to monitor and control your Java application and platform. While it may be acceptable for development, it is not recommended for production systems.When you disable password authentication, you can also disable SSL, as described in Disabling Security. You can also disable passwords, but use SSL client authentication, as described in Enabling SSL Client Authentication.
Using LDAP Authentication
The 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 LoginModule
class with the LdapLoginModule
class.
Create a JAAS configuration file that works in the required business organization. Here is an example of a configuration file (ldap.config
) :
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;
};
Here is an overview of the options mentioned in the configuration file:
- The
com.sun.security.auth.module.LdapLoginModule REQUIRED
option means that authentication usingLdapLoginModule
is required for the overall authentication to be successful. - The
userProvider
option identifies the LDAP server and the position in the directory tree where user entries are located. - The
userFilter
option specifies the search filter to use to locate a user entry in the LDAP directory. The token{USERNAME}
is replaced with the user name before the filter is used to search the directory. - The
authzIdentity
option specifies the access role for authenticated users. In the example, authenticated users will have themonitorRole
option. See Access Files.
The details of the configuration options mentioned in the code example is explained in the com.sun.security.auth.module.LdapLoginModule class.
Start your application with the following properties set on the command line:
com.sun.management.jmxremote.login.config
: This property configures the JMX agent to use the specified JAAS configuration entry.java.security.auth.login.config
: This property specifies the path to the JAAS configuration file.
Here is a sample command line:
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 SSL
SSL is enabled by default when you enable remote monitoring and management, but it needs to be configured.
A keystore
is a secure repository of
cryptographic keys or trusted certificates. A truststore
is where we place
the certificates that we trust. The keytool
command can create and manipulate
both keystores
and truststores
. It can work on a default
store for the user, or a store specified with a command-line option.
Example Scenarios of Configuring SSL
Here are few example scenarios that will help you to configure SSL.
Use a self-signed certificate pair at the JMX agent (server)
- Create a self-signed certificate pair on the JMX
server:
keytool -genkeypair -dname "CN=My Name, OU=Department, O=Company, L=City, S=State, C=Country" -alias jmxservercert -keyalg rsa –keystore /path/to/keystore -storepass mystorepass
Specifying the location of the
keystore
is optional. Thekeytool
uses a defaultkeystore
file.keystore
in the home directory. However, it is recommended to specify thekeystore
location as there could be differentkeystores
for different purposes. - Export the certificate as a file. This exports
the public key from the generated certificate
pair:
keytool -export -alias jmxservercert –keystore /path/to/keystore -storepass mystorepass -rfc -file exported_server_cert
- Copy the exported certificate to the client
(where the attaching tool executes) and import
into a
truststore
:keytool -importcert -alias jmxservercert -file exported_server_cert -storepass mystorepass -keystore myTruststore
- Run the server, specifying the
keystore
and the specific port where JMX is enabled:java -Djavax.net.ssl.keyStore=/path/to/keystore -Djavax.net.ssl.keyStorePassword=mystorepass -Dcom.sun.management.jmxremote.port=<<PORTNUMBER>> MyJavaApp
- Run the client tool, for example
JConsole:
jconsole -J-Djavax.net.ssl.trustStore=myTruststore -J-Djavax.net.ssl.trustStorePassword=mystorepass
- In the New Connection dialog, specify host:port and the configured role name and password. See Using Password and Access Files.
truststore
. This is
within the JDK directory, so may not be appropriate if the JDK is shared, but could be
easier as there is no need to specify a truststore
location or password
when running JConsole. For example:
keytool -importcert -file exported_server_cert
Enabling SSL client authentication
In the Use a self-signed certificate pair at the JMX agent (server) section, the server public certificate proves the identity of the server. In this section, the following procedure permits two-way SSL authentication, where additionally the server has a public certificate from the client as proof of its identity.
Before you begin, create a self-signed
certificate pair at the JMX agent (server) and import that to the
truststore
of the client, as in the steps above. Then:
- At the client, generate a key
pair:
keytool -genkeypair -dname "CN=My Name, OU=Department, O=Company, L=City, S=State, C=Country" -alias jmxservercert -keyalg rsa -storepass mystorepass
- Export the key
pair:
keytool -export -alias jmxclientcert -storepass mystorepass -rfc -file exported_client_cert
- At the JMX server,
import
keytool -importcert -alias jmxclientcert -file exported_client_cert -keystore myTruststore -storepass mystorepass
- Run the JMX server specifying the
truststore
, and thecom.sun.management.jmxremote.ssl.need.client.auth
property:java -Djavax.net.ssl.trustStore=myTruststore -Djavax.net.ssl.trustStorePassword=mystorepass -Djavax.net.ssl.keyStore=/path/to/keystore -Djavax.net.ssl.keyStorePassword=mystorepass -Dcom.sun.management.jmxremote.port=PORTNUMBER -Dcom.sun.management.jmxremote.ssl.need.client.auth=true MyJavaApp
- Run JConsole (the
client):
jconsole -J-Djavax.net.ssl.trustStore=myTruststore -J-Djavax.net.ssl.trustStorePassword=mystorepass
SSL with CA-signed certificates
When a certificate is signed by a Certificate Authority, it can be verified without being exported and imported to the other party.
The general procedure to set up SSL is as follows:
- If you do not have a key pair and certificate
set up on the server, then perform the
following tasks:
-
Generate a key pair with the
keytool -genkey
command. -
Request a signed certificate from a certificate authority (CA) with the
keytool -certreq
command. This creates a Certificate Signing Request (CSR). -
Import the certificate into your keystore with the
keytool -import
command. See the Importing Certificates inkeytool
documentation.
-
- Configure SSL on the server system. Complete
explanation of configuring and customizing SSL is
beyond the scope of this document, but you generally
need to set the system properties as described in
the following list:
javax.net.ssl.keyStore
Keystore location
javax.net.ssl.keyStoreType
Default keystore type
javax.net.ssl.keyStorePassword
Default keystore password
javax.net.ssl.trustStore
Truststore location
javax.net.ssl.trustStoreType
Default truststore type
javax.net.ssl.trustStorePassword
Default truststore password
- Setting system properties is detailed in the Setting System Properties section.
- With this certificate on the server, the client can trust
the server. Similarly, the client can create a key
pair and then a CSR to have it signed by a CA. Then,
the server can trust the client and the
com.sun.management.jmxremote.ssl.need.client.auth
property can be set to true.
See:
- keytool - Key and Certificate Management Tool in the Java Development Kit Tool Specifications
-
Customizing the Default Keystores and Truststores, Store Types, and Store Passwords in Java Platform, Standard Edition Security Developer's Guide
Enabling RMI Registry Authentication
When setting up connections for monitoring remote applications, you can optionally bind the RMI connector stub to an RMI registry that is protected by SSL. This allows clients with the appropriate SSL certificates to get the connector stub that is registered in the RMI registry. To protect the RMI registry using SSL, you must set the following system property:
com.sun.management.jmxremote.registry.ssl=true
When this property is set to true
, an RMI registry protected by SSL will be created and configured by the ready-to-use management agent when the Java VM is started. The default value of this property is false
. However, it is recommended that you set this property to true
. If this property is set to true
, then to have full security, you must also enable SSL client authentication.
Enabling SSL Client Authentication
To enable SSL client authentication, set the following system property when you start the Java VM:
com.sun.management.jmxremote.ssl.need.client.auth=true
SSL must be enabled (default is set to false
) to use client SSL authentication. It is recommended that you set this property to true
. This configuration requires that the client system have a valid digital certificate. You must install a certificate and configure SSL on the client system, as described in Using SSL. As stated in the previous section, if RMI registry SSL protection is enabled, then client SSL authentication must be set to true
.
Disabling SSL
To disable SSL when monitoring remotely, you must set the following system property when you start the Java VM:
com.sun.management.jmxremote.ssl=false
Password authentication will still be required unless you disable it, as specified in Disabling Password Authentication.
Disabling Security
To disable both password authentication and SSL (namely to disable all security), you should set the following system properties when you start the Java VM:
com.sun.management.jmxremote.authenticate=false
com.sun.management.jmxremote.ssl=false
Note:
Caution : This configuration is insecure; any remote user who knows (or guesses) your port number and host name will be able to monitor and control your Java applications and platform. Furthermore, possible harm is not limited to the operations that you define in your MBeans. A remote client could create ajavax.management.loading.MLet
MBean and use it to create new MBeans from arbitrary URLs, at least if there is no security manager. In other words, a remote client can make your Java application execute arbitrary code.
Consequently, while disabling security might be acceptable for development, it is strongly recommended that you do not disable security for production systems.
Remote Monitoring with JConsole
You can remotely monitor an application using JConsole, with or without security enabled.
Remote Monitoring with JConsole with SSL Enabled
To monitor a remote application with SSL enabled, you need to set up the truststore
file on the system where JConsole is running and configure SSL properly. For example, you can create a keystore
file and start your application (called Server
in this example) with the following commands:
% java -Djavax.net.ssl.keyStore=keystore \
-Djavax.net.ssl.keyStorePassword=password Server
See Customizing the Default Keystores and Truststores, Store Types, and Store Passwords in the Java Platform, Standard Edition Security Developer's Guide.
If you create the keystore
file and start the Server
applicaton, then start JConsole as follows:
% jconsole -J-Djavax.net.ssl.trustStore=truststore \
-J-Djavax.net.ssl.trustStorePassword=trustword
See Using JConsole.
The configuration authenticates the server only. If SSL client authentication is set up, then you need to provide a similar keystore
file for JConsole's keys and an appropriate truststore
file for the application.
Using Password and Access Files
The password and access files control security for remote monitoring and management.
These files are located by default in JAVA_HOME/conf/management
and are in the standard Java
properties file format. For more information on the format, see the API reference for
the java.util.Properties
package.
Password Files
The password file defines the different roles and their passwords. The access control file (jmxremote.access
by default) defines the permitted access for each role. To be functional, a role must have an entry in both the password and the access files.
The JDK contains a password file template named jmxremote.password.template
. Copy this file to JAVA_HOME/conf/management/jmxremote.password
in to your home directory and add the passwords for the roles defined in the access file.
You must ensure that only the owner has read and write permissions on this file, because it contains the passwords in clear-text. For security reasons, the system checks that the file is readable only by the owner and exits with an error if it is not. Thus in a multiple-user environment, you should store the password file in a private location such as your home directory.
Property names are roles, and the associated value is the role's password. Example 2–1 shows sample entries in the password file.
Example 2-1 An Example Password File
# specify actual password instead of the text password
monitorRole password
controlRole password
On Linux or macOS operating systems, you can set the file permissions for the password file by running the following command:
chmod 600 jmxremote.password
Access Files
By default, the access file is named jmxremote.access
. Property names are identities from the same space as the password file. The associated value must either be readonly
or readwrite
.
The access file defines roles and their access levels. By default, the access file defines the following primary roles:
-
monitorRole
, which grants read-only access for monitoring. -
controlRole
, which grants read/write access for monitoring and management.
-
readonly
: Grants access to read the MBean's attributes. For monitoring, this means that a remote client in this role can read measurements but cannot perform any action that changes the environment of the running program. The remote client can also listen to MBean notifications. -
readwrite
: Grants access to read and write the MBean's attributes, and to call operations on them. This access should be granted only to trusted clients, because they can potentially interfere with the operation of an application. Thereadwrite
access level can optionally be followed by thecreate
orunregister
keywords. Theunregister
keyword grants access to unregister (delete) MBeans. Thecreate
keyword grants access to create MBeans of a particular class or of any class matching a particular pattern. Access should only be granted to create MBeans of known and trusted classes.
A role should have only one entry in the access file. If a role has no entry, then it has no access. If a role has multiple entries, then the last entry takes precedence. Typical predefined roles in the access file resemble what is shown in the Example 2-2.
Example 2-2 Example Access File
# The "monitorRole" role has readonly access.
# The "controlRole" role has readwrite access.
monitorRole readonly
controlRole readwrite
In Example 2-3, the entry grants readwrite
access to
controlRole
. It also provides access to create MBeans of the class
javax.management.monitor.CounterMonitor
and to unregister any
MBean.
Example 2-3 Example using create
and
unregister
controlRole readwrite \
create javax.management.monitor.CounterMonitorMBean \
unregister
Remote Monitoring with JConsole with SSL Disabled
To monitor a remote application with SSL disabled, start the JConsole with the following command:
% jconsole hostName:portNum
You can also omit the host name and port number, and enter them in the dialog box that JConsole provides.
Ready-to-Use Monitoring and Management Properties
You can set ready-to-use monitoring and management properties in a configuration file
or on the command line. Properties specified on the command line override properties in
a configuration file. The default location for the configuration file is
JAVA_HOME/conf/management/management.properties
. The Java VM reads
this file if any of the command-line properties is set:
-
orcom.sun.management.jmxremote
-
orcom.sun.management.jmxremote.port
-
com.sun.management.jmxremote.local.port
You can specify a different location for the configuration file with the following command-line option:
com.sun.management.config.file=ConfigFilePath
ConfigFilePath
is the path to the configuration file.
Table 2-1 describes the ready-to-use monitoring and management properties.
Table 2-1 Ready-to-Use Monitoring and Management Properties
Property | Description | Values |
---|---|---|
|
Enables the JMX remote agent and local monitoring using a JMX connector. This agent is published on a private interface that is used by JConsole and any other local JMX clients, which use the Attach API. JConsole can use this connector if it is started by the same user who started the agent. No password or access files are checked for requests coming from this connector. |
|
|
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 |
Port number. No default. |
|
Binds the RMI connector stub to an RMI registry that is protected by SSL. |
|
|
Enables secure monitoring using SSL. If the value is |
|
|
Shows a comma-delimited list of SSL/TLS protocol versions to enable. Used in conjunction with |
Default SSL/TLS protocol version. |
|
Shows a comma-delimited list of SSL/TLS cipher suites to enable. Used in conjunction with |
Default SSL/TLS cipher suites. |
|
Performs client authentication if this property is It is recommended that you set this property to |
|
|
Prevents JMX from using password or access files if this property is |
|
|
Specifies the location for the password file. If |
|
|
Specifies the location for the access file. If |
|
|
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 |
Default login configuration is a file-based password authentication. |
com.sun.management.jmxremote.rmi.port |
Specifies the port number to which the RMI connector will be bound. |
Port number. Ensure to use an unused port number. |
com.sun.management.jmxremote.local.port |
Specifies the local port number that accepts local JMX connections. |
Port number. Ensure to use an unused port number. |
Configuration Errors
If any errors occur during the start up of the MBean server, the RMI registry, or the connector, then 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.
Connecting to the JMX Agent Programmatically
After 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, as shown in the Example 2-3.
Example 2-3 Creating a Connection Using JMXConnectorFactory.connect
JMXServiceURL u = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum + "/jmxrmi");
JMXConnector c = JMXConnectorFactory.connect(u);
Setting Up Monitoring and Management Programmatically
You can create a JMX client that uses the Attach API to enable ready-to-use monitoring and management of any applications that are started on the Java SE platform, without having to configure the applications for monitoring when you start them. The Attach API provides a way for tools to attach to and start agents in the target application. After an agent is running, JMX clients (and other tools) are able to obtain the JMX connector address for that agent using 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 Address
static 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) {
vm.startLocalManagementAgent();
// agent is started, get the connector address
connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
}
// establish connection to connector server
JMXServiceURL url = new JMXServiceURL(connectorAddress);
JMXConnector 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
, which you can use to connect to the local JMX agent.
If no agent is running, then one is loaded by the VirtualMachine
class and its connector address is obtained by the getAgentProperties()
method.
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.
Note:
Previous to JDK 11, the Attach API had issues locating JVMs running in docker containers. This is now fixed, and jcmd
and jps
work as expected. However, jmc
will not list java
processes running in separate docker containers. There is no known way to explicitly provide the PID of the java
process to this tool.
Mimicking Ready-to-Use Management Using the JMX Remote API
The remote access to the ready-to-use management agent is protected by authentication and authorization, and by SSL encryption. The configuration is performed by setting system properties or by defining a management.properties
file. In most cases, using the ready-to-use management agent and configuring it through the management.properties
file is 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 multihomed systems. For such cases, the behavior of the ready-to-use management agent can be mimicked by using the JMX Remote API directly to create, configure, and deploy the management agent programmatically.
Example of Mimicking Ready-to-Use Management
This section provides an example of how to implement a JMX agent that identically mimics an ready-to-use management agent. In exactly the same way as the ready-to-use management agent, the agent created in Example 2-5 will run on port 3000. It 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 is explained in Creating a Keystore to Use with JSSE section of Java Platform, Standard Edition Security Developer's Guide.
To enable monitoring and management on an application named com.example.MyApp
, using the ready-to-use JMX agent with the configuration, run the 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:
Thecom.sun.management.jmxremote.*
properties can be 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
is required to specify the location of the management.properties
file.
Example 2-5 shows the code that you need to write to programmatically create a JMX agent, which will allow exactly the same monitoring and management on com.example.MyApp
as using the prior command.
Example 2-5 Mimicking a Ready-to-Use JMX Agent Programmatically
package 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 that the
// ready-to-use management agent uses to register the RMIServer
// stub.
//
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 monitored and managed in exactly the same way as if the Java platform's ready-to-use management agent has been used. However, there is one slight but important difference between the RMI registry used by the ready-to-use management agent and the one used by a management agent that mimics it. The RMI registry used by the ready-to-use management agent is read-only, namely a single entry can be bound to it and upon being bound, this entry cannot be unbound. This is not true with 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 that 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 nontrusted client.
RMI registries that 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 ready-to-use JMX agent, but does not replicate all the existing properties in the management.properties
file. However, you can add other properties by modifying com.example.MyApp
appropriately.
Monitoring Applications Through a Firewall
The code in Example 2-5 can be used to monitor applications through a firewall, which might not be possible if you use the ready-to-use 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 JMXServiceURL
as follows:
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost:" +
port1 + "/jndi/rmi://localhost:" + port2 + "/jmxrmi");
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.
Using an Agent Class to Instrument an Application
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 that
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.
Creating an Agent Class to Instrument an Application
The following procedure shows how you can adapt the code of com.example.MyApp
to create an agent to instrument any other application for monitoring and management.
- Create a
com.example.MyAgent
class.Create a class called
com.example.MyAgent
, declaring apremain
method rather than amain
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 is same as thecom.example.MyApp
class as shown in Example 2-5. - Compile the
com.example.MyAgent
class. - Create a manifest file,
MANIFEST.MF
, with aPremain-Class
entry.An agent is deployed as a Java archive (JAR) file. An attribute in the JAR file manifest specifies the agent class that will be loaded to start the agent. Create a file called
MANIFEST.MF
, containing the following line:Premain-Class: com.example.MyAgent
- Create a JAR file,
MyAgent.jar
.The JAR file should contain the following files:
-
META-INF/MANIFEST.MF
-
com/example/MyAgent.class
-
- Start an application, specifying the agent to provide monitoring and management services.
You can use
com.example.MyAgent
to instrument any application for monitoring and management. This example uses theNotepad
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 startNotepad
. Also, if yourcom.example.MyAgent
application replicates the same code as thecom.example.MyApp
application shown in Example 2-5, then provide thekeystore
andpassword
information because the RMI connector server is protected by SSL.