Merge branch 'jetty-9.4.x'

This commit is contained in:
WalkerWatch 2017-10-31 12:58:56 -04:00
commit 0f540e13ac
1 changed files with 50 additions and 129 deletions

View File

@ -18,53 +18,33 @@
=== Using JMX with Jetty === Using JMX with Jetty
Jetty's architecture is based on POJO components (see xref:basic-architecture[]). Jetty's architecture is based on POJO components (see xref:basic-architecture[]).
These components are organized in a tree and each component may have a lifecycle These components are organized in a tree and each component may have a lifecycle that spans the `Server` lifetime, or a web application lifetime, or even shorter lifetimes such as that of a TCP connection.
that spans the `Server` lifetime, or a web application lifetime, or even shorter
lifetimes such as that of a TCP connection.
Every time a component is added or removed from the component tree, an event is Every time a component is added or removed from the component tree, an event is emitted, and link:{JDURL}/org/eclipse/jetty/util/component/Container.html[`Container.Listener`] implementations can listen to those events and perform additional actions.
emitted, and link:{JDURL}/org/eclipse/jetty/util/component/Container.html[`Container.Listener`]
implementations can listen to those events and perform additional actions.
One such `Container.Listener` is `MBeanContainer` that uses `ObjectMBean` to One such `Container.Listener` is `MBeanContainer` that uses `ObjectMBean` to create an MBean from an arbitrary POJO, and register/unregister the MBean to/from the platform `MBeanServer`.
create an MBean from an arbitrary POJO, and register/unregister the MBean to/from
the platform `MBeanServer`.
Jetty components are annotated with <<jetty-jmx-annotations,JMX annotations>> Jetty components are annotated with xref:jetty-jmx-annotations[] and provide specific JMX details so that `ObjectMBean` can build a more precise representation of the JMX metadata associated with the component POJO.
and provide specific JMX details so that `ObjectMBean` can build a more
precise representation of the JMX metadata associated with the component POJO.
Therefore, when a component is added to the component tree, `MBeanContainer` is Therefore, when a component is added to the component tree, `MBeanContainer` is notified, it creates the MBean from the component POJO and registers it to the `MBeanServer`.
notified, it creates the MBean from the component POJO and registers it to Similarly, when a component is removed from the tree, `MBeanContainer` is notified, and unregisters the MBean from the `MBeanServer`.
the `MBeanServer`.
Similarly, when a component is removed from the tree, `MBeanContainer` is
notified, and unregisters the MBean from the `MBeanServer`.
The Jetty MBeans can be accessed via any JMX console such as Java Mission Control The Jetty MBeans can be accessed via any JMX console such as Java Mission Control (JMC), VisualVM, JConsole or others.
(JMC), VisualVM, JConsole or others.
[[configuring-jmx]] [[configuring-jmx]]
==== Configuring JMX ==== Configuring JMX
This guide describes the various ways to initialize and configure the Jetty JMX integration. This guide describes the various ways to initialize and configure the Jetty JMX integration.
Configuring the Jetty JMX integration only registers the Jetty MBeans into the platform Configuring the Jetty JMX integration only registers the Jetty MBeans into the platform `MBeanServer`, and therefore the MBeans can only be accessed locally (from the same machine), not from remote machines.
`MBeanServer`, and therefore the MBeans can only be accessed locally (from the same machine),
not from remote machines.
This means that this configuration is enough for development, where you have easy access This means that this configuration is enough for development, where you have easy access (with graphical user interface) to the machine where Jetty runs, but it is typically not enough when the machine Jetty where runs is remote, or only accessible via SSH or otherwise without graphical user interface support.
(with graphical user interface) to the machine where Jetty runs, but it is typically not In these cases, you have to enable link:#jmx-remote-access[JMX Remote Access].
enough when the machine Jetty where runs is remote, or only accessible via SSH or otherwise
without graphical user interface support.
In these cases, you have to enable <<jmx-remote-access,JMX remote access>>.
[[jmx-standalone-jetty]] [[jmx-standalone-jetty]]
===== Standalone Jetty Server ===== Standalone Jetty Server
JMX is not enabled by default in the Jetty distribution. JMX is not enabled by default in the Jetty distribution.
To enable JMX in the Jetty distribution run the following, where `{$jetty.home}` To enable JMX in the Jetty distribution run the following, where `{$jetty.home}` is the directory where you have the Jetty distribution installed, and `${jetty.base}` is the directory where you have your Jetty configuration (see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):
is the directory where you have the Jetty distribution installed, and
`${jetty.base}` is the directory where you have your Jetty configuration
(see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
@ -72,14 +52,12 @@ $ cd ${jetty.base}
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx $ java -jar {$jetty.home}/start.jar --add-to-start=jmx
---- ----
Running the above command will append the available configurable elements of the `jmx` module Running the above command will append the available configurable elements of the `jmx` module to the `{$jetty.base}/start.ini` file, or create the `${jetty.base}/start.d/jmx.ini` file.
to the `{$jetty.base}/start.ini` file, or create the `${jetty.base}/start.d/jmx.ini` file.
[[jmx-embedded-jetty]] [[jmx-embedded-jetty]]
===== Embedded Jetty Server ===== Embedded Jetty Server
When running Jetty embedded into an application, create and configure an `MBeanContainer` When running Jetty embedded into an application, create and configure an `MBeanContainer` instance as follows:
instance as follows:
[source, java] [source, java]
---- ----
@ -93,17 +71,12 @@ server.addBean(mbeanContainer);
server.addBean(Log.getLog()); server.addBean(Log.getLog());
---- ----
Because logging is initialized prior to the `MBeanContainer` (even before the `Server` itself), Because logging is initialized prior to the `MBeanContainer` (even before the `Server` itself), it is necessary to register the logger manually via `server.addBean()` so that the loggers may show up in the JMX tree as MBeans.
it is necessary to register the logger manually via `server.addBean()` so that the loggers may
show up in the JMX tree as MBeans.
[[jmx-jetty-maven-plugin]] [[jmx-jetty-maven-plugin]]
===== Using the Jetty Maven Plugin with JMX ===== Using the Jetty Maven Plugin with JMX
If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the `${jetty.home}/etc/jetty-jmx.xml` file into your webapp project somewhere, such as `src/main/config/etc/`, then add a `<jettyXml>` element to the `<configuration>` element of the Jetty Maven Plugin:
`${jetty.home}/etc/jetty-jmx.xml` file into your webapp project somewhere, such as
`src/main/config/etc/`, then add a
`<jettyXml>` element to the `<configuration>` element of the Jetty Maven Plugin:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -121,39 +94,30 @@ If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should cop
[[accessing-jetty-mbeans]] [[accessing-jetty-mbeans]]
==== Using JConsole or Java Mission Control to Access Jetty MBeans ==== Using JConsole or Java Mission Control to Access Jetty MBeans
The simplest way to access the MBeans that Jetty publishes is to use The simplest way to access the MBeans that Jetty publishes is to use link:#jetty-jconsole[Java Mission Control (JMC) or JConsole.]
<<jetty-jconsole,Java Mission Control (JMC) or JConsole>>.
Both these tools can connect to local or remote JVMs to display the MBeans. Both these tools can connect to local or remote JVMs to display the MBeans.
For local access, you just need to start JConsole or JMC and then choose For local access, you just need to start JConsole or JMC and then choose from their user interface the local JVM you want to connect to.
from their user interface the local JVM you want to connect to.
For remote access, you need first to enable <<jmx-remote-access,JMX remote access>> For remote access, you need first to enable JMX Remote Access in Jetty.
in Jetty.
[[jmx-remote-access]] [[jmx-remote-access]]
==== Enabling JMX Remote Access ==== Enabling JMX Remote Access
There are two ways of enabling remote connectivity so that JConsole or JMC can connect There are two ways of enabling remote connectivity so that JConsole or JMC can connect to the remote JVM to visualize MBeans.
to the remote JVM to visualize MBeans.
* Use the `com.sun.management.jmxremote` system property on the command line. * Use the `com.sun.management.jmxremote` system property on the command line.
Unfortunately, this solution does not work well with firewalls and is not flexible. Unfortunately, this solution does not work well with firewalls and is not flexible.
* Use Jetty's `jmx-remote` module or - equivalently - the `ConnectorServer` class. * Use Jetty's `jmx-remote` module or - equivalently - the `ConnectorServer` class.
`ConnectorServer` will use by default RMI to allow connection from remote clients, `ConnectorServer` will use by default RMI to allow connection from remote clients,
and it is a wrapper around the standard JDK class `JMXConnectorServer`, which is and it is a wrapper around the standard JDK class `JMXConnectorServer`, which is the class that provides remote access to JMX clients.
the class that provides remote access to JMX clients.
Connecting to the remote JVM is a two step process: Connecting to the remote JVM is a two step process:
* First, the client will connect to the RMI _registry_ to download the RMI stub for * First, the client will connect to the RMI _registry_ to download the RMI stub for the `JMXConnectorServer`; this RMI stub contains the IP address and port to connect to the RMI server, i.e. the remote `JMXConnectorServer`.
the `JMXConnectorServer`; this RMI stub contains the IP address and port to connect * Second, the client uses the RMI stub to connect to the RMI _server_ (i.e. the remote `JMXConnectorServer`) typically on an address and port that may be different from the RMI registry address and port.
to the RMI server, i.e. the remote `JMXConnectorServer`.
* Second, the client uses the RMI stub to connect to the RMI _server_ (i.e. the
remote `JMXConnectorServer`) typically on an address and port that may be different
from the RMI registry address and port.
The configuration for the RMI registry and the RMI server is specified by a `JMXServiceURL`. The configuration for the RMI registry and the RMI server is specified by a `JMXServiceURL`.
The string format of an RMI `JMXServiceURL` is: The string format of an RMI `JMXServiceURL` is:
@ -173,19 +137,13 @@ rmi_registry_host = localhost
rmi_registry_port = 1099 rmi_registry_port = 1099
---- ----
With the default configuration, only clients that are local to the server machine can connect With the default configuration, only clients that are local to the server machine can connect to the RMI registry and RMI server - this is done for security reasons.
to the RMI registry and RMI server - this is done for security reasons. With this configuration it would still be possible to access the MBeans from remote using a link:#jmx-remote-access-ssh-tunnel[SSH tunnel.]
With this configuration it would still be possible to access the MBeans from remote using
a <<jmx-remote-access-ssh-tunnel,SSH tunnel>>.
By specifying an appropriate `JMXServiceURL`, you can fine tune the network interfaces the By specifying an appropriate `JMXServiceURL`, you can fine tune the network interfaces the RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server listen to.
RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server The RMI server and RMI registry hosts and ports can be the same (as in the default configuration) because RMI is able to multiplex traffic arriving to a port to multiple RMI objects.
listen to.
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration)
because RMI is able to multiplex traffic arriving to a port to multiple RMI objects.
If you need to allow JMX remote access through a firewall, you must open both the RMI registry If you need to allow JMX remote access through a firewall, you must open both the RMI registry and the RMI server ports.
and the RMI server ports.
Examples: Examples:
@ -213,21 +171,15 @@ service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi
[NOTE] [NOTE]
==== ====
When `ConnectorServer` is started, its RMI stub is exported to the RMI registry. When `ConnectorServer` is started, its RMI stub is exported to the RMI registry.
The RMI stub contains the IP address and port to connect to the RMI object, but The RMI stub contains the IP address and port to connect to the RMI object, but the IP address is typically the machine host name, not the host specified in the `JMXServiceURL`.
the IP address is typically the machine host name, not the host specified in the
`JMXServiceURL`.
To control the IP address stored in the RMI stub you need to set the system To control the IP address stored in the RMI stub you need to set the system property `java.rmi.server.hostname` with the desired value.
property `java.rmi.server.hostname` with the desired value. This is especially important when binding the RMI server host to the loopback address for security reasons. See also link:#jmx-remote-access-ssh-tunnel[JMX Remote Access via SSH Tunnel.]
This is especially important when binding the RMI server host to the loopback
address for security reasons. See also
<<jmx-remote-access-ssh-tunnel,JMX Remote Access via SSH Tunnel>>.
==== ====
===== Enabling JMX Remote Access in Standalone Jetty Server ===== Enabling JMX Remote Access in Standalone Jetty Server
Similarly to <<jmx-standalone-jetty,enabling JMX in a standalone Jetty server>>, you Similarly to <<jmx-standalone-jetty,enabling JMX in a standalone Jetty server>>, you enable the `jmx-remote` module:
enable the `jmx-remote` module:
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
---- ----
@ -253,19 +205,15 @@ ConnectorServer jmxServer = new ConnectorServer(jmxURL, "org.eclipse.jetty.jmx:n
server.addBean(jmxServer); server.addBean(jmxServer);
---- ----
The `JMXServiceURL` above specifies that the RMI server binds to the wildcard address The `JMXServiceURL` above specifies that the RMI server binds to the wildcard address on port 1999, while the RMI registry binds to the wildcard address on port 1099 (the default RMI registry port).
on port 1999, while the RMI registry binds to the wildcard address on port 1099 (the
default RMI registry port).
[[jmx-remote-access-authorization]] [[jmx-remote-access-authorization]]
===== JMX Remote Access Authorization ===== JMX Remote Access Authorization
The standard `JMXConnectorServer` provides several options to authorize access. The standard `JMXConnectorServer` provides several options to authorize access.
For a complete guide to controlling authentication and authorization in JMX, see For a complete guide to controlling authentication and authorization in JMX, see https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors].
https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors].
To authorize access to the `JMXConnectorServer` you can use this configuration, To authorize access to the `JMXConnectorServer` you can use this configuration, where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:
where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -311,16 +259,13 @@ ConnectorServer jmxServer = new ConnectorServer(jmxURL, env, "org.eclipse.jetty.
jmxServer.start(); jmxServer.start();
---- ----
Calling `ConnectorServer.start()` may be explicit as in the examples above, Calling `ConnectorServer.start()` may be explicit as in the examples above, or can be skipped when adding the `ConnectorServer` as a bean to the `Server`, so that starting the `Server` will also start the `ConnectorServer`.
or can be skipped when adding the `ConnectorServer` as a bean to the `Server`,
so that starting the `Server` will also start the `ConnectorServer`.
===== Securing JMX Remote Access with TLS ===== Securing JMX Remote Access with TLS
The JMX communication via RMI happens by default in clear-text. The JMX communication via RMI happens by default in clear-text.
It is possible to configure the `ConnectorServer` with a `SslContextFactory` so It is possible to configure the `ConnectorServer` with a `SslContextFactory` so that the JMX communication via RMI is encrypted:
that the JMX communication via RMI is encrypted:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -351,33 +296,20 @@ JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi
ConnectorServer jmxServer = new ConnectorServer(jmxURL, null, "org.eclipse.jetty.jmx:name=rmiconnectorserver", sslContextFactory); ConnectorServer jmxServer = new ConnectorServer(jmxURL, null, "org.eclipse.jetty.jmx:name=rmiconnectorserver", sslContextFactory);
---- ----
It is possible to use the same `SslContextFactory` used to configure the It is possible to use the same `SslContextFactory` used to configure the Jetty `ServerConnector` that supports TLS for the HTTP protocol.
Jetty `ServerConnector` that supports TLS for the HTTP protocol. This is used in the XML example above: the `SslContextFactory` configured for the TLS `ServerConnector` is registered with an id of `sslContextFactory` which is referenced in the XML via the `Ref` element.
This is used in the XML example above: the `SslContextFactory` configured
for the TLS `ServerConnector` is registered with an id of `sslContextFactory`
which is referenced in the XML via the `Ref` element.
The keystore must contain a valid certificate signed by a Certification Authority. The keystore must contain a valid certificate signed by a Certification Authority.
The RMI mechanic is the usual one: the RMI client (typically a monitoring console) The RMI mechanic is the usual one: the RMI client (typically a monitoring console) will connect first to the RMI registry (using TLS), download the RMI server stub that contains the address and port of the RMI server to connect to, then connect to the RMI server (using TLS).
will connect first to the RMI registry (using TLS), download the RMI server stub
that contains the address and port of the RMI server to connect to, then connect
to the RMI server (using TLS).
This also mean that if the RMI registry and the RMI server are on different hosts, This also mean that if the RMI registry and the RMI server are on different hosts, the RMI client must have available the cryptographic material to validate both hosts.
the RMI client must have available the cryptographic material to validate both
hosts.
Having certificates signed by a Certification Authority simplifies by a lot the Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the JMX communication over TLS working properly.
configuration needed to get the JMX communication over TLS working properly.
If that is not the case (for example the certificate is self-signed), then you If that is not the case (for example the certificate is self-signed), then you need to specify the required system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.
need to specify the required system properties that allow RMI (especially when
acting as an RMI client) to retrieve the cryptographic material necessary to
establish the TLS connection.
For example, trying to connect using the JDK standard `JMXConnector` with both For example, trying to connect using the JDK standard `JMXConnector` with both the RMI server and the RMI registry to `domain.com`:
the RMI server and the RMI registry to `domain.com`:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -402,19 +334,14 @@ Similarly, to launch JMC:
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret $ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret
---- ----
Note that these system properties are required when launching the `ConnectorServer` too, Note that these system properties are required when launching the `ConnectorServer` too, on the server, because it acts as an RMI client with respect to the RMI registry.
on the server, because it acts as an RMI client with respect to the RMI registry.
[[jmx-remote-access-ssh-tunnel]] [[jmx-remote-access-ssh-tunnel]]
===== JMX Remote Access with Port Forwarding via SSH Tunnel ===== JMX Remote Access with Port Forwarding via SSH Tunnel
You can access JMX MBeans on a remote machine when the RMI ports are not open, You can access JMX MBeans on a remote machine when the RMI ports are not open, for example because of firewall policies, but you have SSH access to the machine using local port forwarding via a SSH tunnel.
for example because of firewall policies, but you have SSH access to the machine
using local port forwarding via a SSH tunnel.
In this case you want to configure the `ConnectorServer` with a `JMXServiceURL` In this case you want to configure the `ConnectorServer` with a `JMXServiceURL` that binds the RMI server and the RMI registry to the loopback interface only: `service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi`.
that binds the RMI server and the RMI registry to the loopback interface only:
`service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi`.
Then you setup the local port forwarding with the SSH tunnel: Then you setup the local port forwarding with the SSH tunnel:
@ -423,15 +350,9 @@ Then you setup the local port forwarding with the SSH tunnel:
$ ssh -L 1099:localhost:1099 <user>@<machine_host> $ ssh -L 1099:localhost:1099 <user>@<machine_host>
---- ----
Now you can use JConsole or JMC to connect to `localhost:1099` on your local Now you can use JConsole or JMC to connect to `localhost:1099` on your local computer.
computer. The traffic will be forwarded to `machine_host` and when there, The traffic will be forwarded to `machine_host` and when there, SSH will forward the traffic to `localhost:1099`, which is exactly where the `ConnectorServer` listens.
SSH will forward the traffic to `localhost:1099`, which is exactly where
the `ConnectorServer` listens.
When you configure `ConnectorServer` in this way, you must set the system When you configure `ConnectorServer` in this way, you must set the system property `-Djava.rmi.server.hostname=localhost`, on the server.
property `-Djava.rmi.server.hostname=localhost`, on the server.
This is required because when the RMI server is exported, its address and This is required because when the RMI server is exported, its address and port are stored in the RMI stub. You want the address in the RMI stub to be `localhost` so that when the RMI stub is downloaded to the remote client, the RMI communication will go through the SSH tunnel.
port are stored in the RMI stub. You want the address in the RMI stub to be
`localhost` so that when the RMI stub is downloaded to the remote client,
the RMI communication will go through the SSH tunnel.