Security
Security in JSR-160 remoting is an all-or-nothing option. Either all or none of your MBeans are accessible (except when your application server uses a SecurityManager, but that is not often the case). Jolokia, on the other hand, allows for fine grained security defined in an XML security policy file. It allows for access restrictions on MBean names (or patterns), attributes, operations, source IP address (or a subnet) and type of Jolokia operation.
Policy based security
Access to MBean and to the Jolokia agents in general can be restricted with an XML policy file. This policy can be configured for various parameters and is divided into several sections.
IP based restrictions
Overall access can be granted based on the IP address of an
HTTP client. These restrictions are
specified within a <remote>
section,
which contains one or more <host>
elements. The source can be given either as an IP address,
a host name, or a netmask given in
CIDR format
(e.g. 10.0.0.0/16
for all clients coming from the 10.0
network). The following allows access from localhost and all
clients whose IP addresses start with "10.0". For all other
IP addresses access is denied.
<remote>
<host>localhost</host>
<host>10.0.0.0/16</host>
</remote>
Commands
This section specifies the Jolokia commands for which access
is generally granted. For each command in the list, access can
be further restricted within the
<deny>
part and each command
missing in the list, which is forbidden globally, can be
selectively enabled for certain MBeans in the
<allow>
section. If the
<commands>
section is missing
completely, access to all commands is allowed.
All Jolokia commands described in Jolokia Protocol can be used in this section:
- read
-
Reading of MBean attributes
- write
-
Setting of MBean attributes
- exec
-
Execution of JMX operations
- list
-
List the available MBeans along with their supported
- search
-
Searching for MBeans
- notification
-
New in Jolokia 2 Subscribing to and receiving notifications
- version
-
Getting version and server information
In the following example, access is granted to the
read
, list
,
search
and version
command, but
not to write
, notification
and exec
operations.
<commands>
<command>read</command>
<command>list</command>
<command>version</command>
<command>search</command>
</commands>
Allow and deny access to certain MBeans
Within an <allow>
section, access
to MBeans can be granted regardless of the
operations specified in the
<commands>
section. The reverse is
true for the <deny>
section: It
rejects access to the MBeans specified here. Both sections
contain one or more <mbean>
elements which have a format like:
<mbean>
<name>java.lang:type=Memory</name>
<attribute>*Memory*</attribute>
<attribute mode="read">Verbose</attribute>
<operation>gc</operation>
</mbean>
Within the <name>
section the name
of the MBean is specified. This can be either a complete
ObjectName or a MBean pattern containing wildcards. The
value given here must conform to the JMX specification for a
valid ObjectName
. On this MBean (or
MBeans if name
is a pattern),
attributes are specified within one or more
<attribute>
elements and operations
within one or more <operation>
elements. The content can also be a pattern, which uses a wildcard
*
. e.g. <attribute>*</attribute>
specifies all attributes on the given MBean. If for an
<attribute>
element the XML
attribute mode="read"
is given, then this
attribute can be accessed only read-only.
HTTP method restrictions
Finally, access can be restricted based on the HTTP method
with which an Jolokia request was received with the
<http>
element. Method allowed
(post
or get
) are
specified with an <method>
inner
element. The following example restricts the access to POST
requests only:
<http>
<method>post</method>
</http>
It the <http>
section is missing
completely, any HTTP method can be used.
Cross-Origin Resource Sharing (CORS) restrictions
Jolokia (since version 1.0.3) supports the W3C specification for Cross-Origin Resource Sharing (also known as "CORS") which allows browser to access resources which are located on a different server than the calling script is loaded from. This specification provides a controlled way to come around the _same origin policy. Most contemporary browsers support CORS.
By default Jolokia allows cross origin access from any
host. This can be limited to certain hosts by using
<allow-origin>
sections within a
<cors>
sections. This tags can
contain the origin URL provided by browsers with the
Origin:
header literally or a
wildcard specification with *
.
<cors>
<!-- Allow cross origin access from www.jolokia.org ... -->
<allow-origin>https://www.jolokia.org</allow-origin>
<!-- ... and all servers from jmx4perl.org with any protocol -->
<allow-origin>*://*.jmx4perl.org</allow-origin>
<!-- Check for the proper origin on the server side, too -->
<strict-checking/>
<!-- Use if Origin header can use https while the protocol is http (e.g., with TLS proxy) -->
<ignore-scheme/>
</cors>
If the option <strict-checking/>
is given in this section, too, then the given patterns
are not only used for CORS checking but also every request is checked on the server side whether the
Origin:
or Referer:
header matches one of the given patterns.
If neither Origin:
nor Referer:
is given and strict checking is enabled, then the access is denied. This useful for protecting against Cross-Site Request Forgery.
Please note that <strict-checking/>
might not be good enough because of potential
browser bugs which could allow to forge the origin header. Examples of these issues are
arbitrary header injection
or referer and origin spoofing. User facing application which uses Jolokia has backend should consider to implement
additional measures like using the
same-site flag
on the session cookie.
If the option <ignore-scheme/>
is specified (it defaults to false
when not used), Origin
header using https
scheme is not restricted to be used with https
protocol only. This option may be required when Jolokia resides behind TLS proxy.
Disable listing/searching of selected MBeans
Using <filter>
element we can filter out results of list
and search
operations (even if search parameters include such MBean names). It’s not preventing users to access given MBeans unless specific <deny>
element is present, but it may
be used to make list
/search
results shorter.
- NOTE
-
This configuration option is available since Jolokia 2.1.0
Here’s the example:
<filter>
<mbean>java.lang:type=MemoryPool</mbean>
<mbean>org.apache.logging.log4j2:*</mbean>
</filter>
The pattern format is not exactly the same as the patter used for javax.management.MBeanServerConnection.queryNames()
. Here’s a summary of rules:
-
*
is a glob matching any number of characters except:
,=
or,
(that’s specific to the format ofObjectName
) -
when there’s no
:
in MBean pattern, entire pattern is treated as domain and all MBeans within matching domain are filtered out -
domain:*
is the same asdomain
pattern and simply means all MBeans within a domain -
domain:type=SomeType
filters out MBeans withindomain
withtype
attribute equal toSomeType
. For the purpose ofMBeanServer.queryNames()
the pattern would bedomain:type=SomeType,*
-
domain:address=*
filters out MBeans withindomain
with any value ofaddress
attribute -
domain:address=Admin*
filters out MBeans withindomain
with value ofaddress
attribute starting withAdmin
Jolokia uses the above patterns individually for each ObjectName
and uses these methods:
-
javax.management.ObjectName.getDomain()
to access the domain -
javax.management.ObjectName.getKeyPropertyList()
andjavax.management.ObjectName.getKeyProperty()
to filter by attributes
For performance purposes there are some restrictions for using *
within a pattern:
-
attribute keys can’t use
*
-
there can be only one
*
within attribute value or domain name (Admin*
,*Admin
,Adm*in
are correct, but*Admi*n*
is not) -
domain:*
is simply treated asdomain
and matches (filters out) all MBeans within a domain
Example for a security policy
The following complete example applies various access restrictions:
-
Access is only allowed for clients coming from localhost
-
Only HTTP Post requests are allowed
-
By default, only
read
andlist
requests are allowed. -
A single
exec
request is allowed for triggering garbage collection. -
Read access to the C3P0 connection pool is restricted to forbid fetching the pool’s properties, which in fact contains the DB password as clear text.
-
Access to
jdk.management.jfr:type=FlightRecorder
MBean is denied (see CVE-2022-41678)
<?xml version="1.0" encoding="utf-8"?>
<restrict>
<remote>
<host>127.0.0.1</host>
</remote>
<http>
<method>post</method>
</http>
<commands>
<command>read</command>
<command>list</command>
</commands>
<allow>
<mbean>
<name>java.lang:type=Memory</name>
<operation>gc</operation>
</mbean>
</allow>
<deny>
<mbean>
<name>com.mchange.v2.c3p0:type=PooledDataSource,*</name>
<attribute>properties</attribute>
</mbean>
<mbean>
<name>jdk.management.jfr:type=FlightRecorder</name>
<attribute>*</attribute>
<operation>*</operation>
</mbean>
</deny>
<filter>
<mbean>java.lang:type=MemoryPool</mbean>
<mbean>org.apache.logging.log4j2:*</mbean>
</filter>
</restrict>
Policy Location
But how do the agents lookup the policy file? By default,
the agents will lookup for a policy file top-level in the
classpath under the name
jolokia-access.xml
. Hence for the war
agent, the policy file must be packaged within the war at
WEB-INF/classes/jolokia-access.xml
, for
all other agents at
/jolokia-access.xml
. The location can
be overwritten with the configuration parameter
policyLocation
, which has to be set
differently depending on the agent type. Please refer to
Agents for more details. The value of this
init parameter can be any URL which can loaded by the JVM. A
special case is an URL with the scheme
classpath:
which results in a lookup of
the policy file within the classpath. As stated above, the
default value of this parameter is
classpath:/jolokia-access.xml
. If a
non-classpath URL is provided with this parameter, and the
target policy file could not be found then access is
completely denied. If a classpath lookup fails then access
is globally granted and a warning is given on standard
output.
The parameter specified with policyLocation
can contain placeholders:
-
$ip
: IP - Address -
$host
: Host - Address -
${prop:foo}
: System property foo -
${env:FOO}
: Environment variable FOO
Jolokia Restrictors
In order to provide fine grained security, Jolokia is using the
abstract concept of an Restrictor. It is
represented by the Java interface
org.jolokia.server.core.service.api.Restrictor
and
comes with several implementations. The most prominent one is
the PolicyRestrictor
which is described
in Policy based security. This is also the
restrictor which is active by default. For special needs, it is
possible to provide a custom implementation of this
interface for the WAR and OSGi agents. It is recommended to
subclass either
org.jolokia.server.core.restrictor.AllowAllRestrictor
or
org.jolokia.server.core.restrictor.DenyAllRestrictor
.
For the WAR agent (Jakarta EE Agent (WAR)), a subclass
of org.jolokia.server.core.http.AgentServlet
should
be created which overrides the
createRestrictor()
public class RestrictedAgentServlet extends AgentServlet {
@Override
protected Restrictor createRestrictor(Configuration pConfig, LogHandler pLogHandler) {
String policyLocation = pConfig.getConfig(ConfigKey.POLICY_LOCATION);
return new MyOwnRestrictor(policyLocation, ...);
}
}
pConfig
is a configuration object from which we can get a URL pointing to the
policy file, which is either the default value
classpath:/jolokia-access.xml
or the
value specified with the init parameter
policyLocation
. This servlet can then be
easily configured in a custom web.xml
the same way as the Jolokia WAR agent.
For programmatic usage there is an even simpler way:
AgentServlet
provides a constructor
which takes an restrictor as argument, so no subclassing is
required in this case.
For an OSGi agent (OSGi Agents),
org.jolokia.server.core.osgi.OsgiAgentServlet
is the proper extension point. It can be subclassed the same
way as shown above and allows a restrictor implementation as
constructor parameter, too. In contrast to
AgentServlet
this class is also OSGi
exported and can be referenced from other
bundles. Additionally, the OSGi agent can also pick up a
restrictor as an OSGi service. See
OSGi Agents for details.