Best practices and recommendations on securing a production TDS/Tomcat server:
manager
ApplicationSHUTDOWN
PortYou should know how to do a basic installation of Tomcat, Java, and the TDS; and be familiar with the Tomcat directory structure; Tomcat server configuration; and the Tomcat manager application.
tomcat-announce
which is a low volume list for release announcements and security vulnerabilities.
thredds
mailing listThe JVM doesn't fork at all, nor does it support setuid()
calls. The JVM, and therefore Tomcat, is one process. The JVM is a virtual machine
with many threads under the same process.
root
user unless
they are all are run as the root
user. Hence, any programs run in Tomcat (TDS, manager
application, other JSPs and servlets)
will run as the root
user.
root
user, and an attacker manages to exploit a weakness in Tomcat or something running in
webapps/
to run arbitrary commands, those commands will be run as the superuser!
root
user and recommend creating an unprivileged, dedicated user and group for running
the Tomcat process.
In this example, both the user and group names will be names tomcat
, and the user's home directory, aka ${tomcat_home}
, is /opt/tomcat
(notice the symlink below). The groupadd and useradd commands were run as the root:
# groupadd tomcat # useradd -g tomcat -d /opt/tomcat tomcat # passwd tomcat
${tomcat_home}
.
${tomcat_home}
${tomcat_home}
to the tomcat
user and tomcat
group:# cd /opt # chown -R tomcat:tomcat apache-tomcat-8.0.24 # ls -ld *tomcat* drwxr-xr-x 9 tomcat tomcat 4096 Jul 15 16:03 apache-tomcat-8.0.24
${tomcat_home}/conf
directory to be owned by the root
user, have a group of tomcat
and have a permission of user/group read only:
# cd /opt/tomcat # ls -l total 92 drwxr-xr-x 2 tomcat tomcat 4096 Jul 15 16:05 bin drwxr-xr-x 2 tomcat tomcat 4096 Jul 18 12:18 conf drwxr-xr-x 2 tomcat tomcat 4096 Jul 15 16:03 lib drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 logs drwxr-xr-x 2 tomcat tomcat 4096 Jul 15 16:03 temp drwxr-xr-x 7 tomcat tomcat 4096 Jul 15 16:04 webapps drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 work # chown -R root:tomcat conf # chmod -R 440 conf/* # ls -l conf total 92 -r--r----- 1 root tomcat 9978 Feb 2 12:06 catalina.policy -r--r----- 1 root tomcat 3713 Feb 2 12:06 catalina.properties -r--r----- 1 root tomcat 1395 Feb 2 12:06 context.xml -r--r----- 1 root tomcat 1353 Jul 18 12:14 keystore -r--r----- 1 root tomcat 3257 Feb 2 12:06 logging.properties -r--r----- 1 root tomcat 6814 Jul 18 12:18 server.xml -r--r----- 1 root tomcat 210 Jul 18 12:10 tomcat-users.xml -r--r----- 1 root tomcat 51835 Feb 2 12:06 web.xml
${tomcat_home}/bin
and ${tomcat_home}/lib
directories to be owned by the root
user
and have a group of tomcat
:
# chown -R root:tomcat lib # chown -R root:tomcat bin # ls -l total 92 drwxr-xr-x 2 root tomcat 4096 Jul 15 16:05 bin drwxr-xr-x 2 root tomcat 4096 Jul 18 12:18 conf drwxr-xr-x 2 root tomcat 4096 Jul 15 16:03 lib drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 logs drwxr-xr-x 2 tomcat tomcat 4096 Jul 15 16:03 temp drwxr-xr-x 7 tomcat tomcat 4096 Jul 15 16:04 webapps drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 work
${tomcat_home}/conf
directory and its subdirectories to give the root
user and tomcat
group read/write permissions. (Depending on the web applications you are running and/or your virtual host configurations, Tomcat will create a ${tomcat_home}/conf/Catalina
) directory with corresponding subdirectories and files for context information. Allowing the tomcat
group to write to ${tomcat_home}/conf
allow this and prevent errors from appearing in your Tomcat logs.)
# pwd # /opt/apache-tomcat-8.0.24 # find conf -type d -exec chmod 775 {} \; -print # ls -l total 220 total 92 drwxr-xr-x 2 root tomcat 4096 Jul 15 16:05 bin drwxrwxr-x 2 root tomcat 4096 Jul 18 12:18 conf drwxr-xr-x 2 root tomcat 4096 Jul 15 16:03 lib drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 logs drwxr-xr-x 2 tomcat tomcat 4096 Jul 15 16:03 temp drwxr-xr-x 7 tomcat tomcat 4096 Jul 15 16:04 webapps drwxr-xr-x 2 tomcat tomcat 4096 Feb 2 12:04 work
${tomcat_home}/conf
directory to give the root
user and tomcat
group has read-only permissions:
# cd conf # find . -type f -exec chmod 440 {} \; -print # ls -l total 220 drwxr-xr-x 3 root tomcat 4096 2013-12-26 15:24 Catalina -r--r----- 1 root tomcat 12374 2015-07-01 14:23 catalina.policy -r--r----- 1 root tomcat 7086 2015-07-01 14:23 catalina.properties -r--r----- 1 root tomcat 1577 2015-07-01 14:23 context.xml -r--r----- 1 root tomcat 2899 2015-04-17 15:42 logging.properties -r--r----- 1 root tomcat 2330 2015-04-22 10:33 server.xml -r--r----- 1 root tomcat 1460 2015-04-24 14:33 tomcat-users.xml -r--r----- 1 root tomcat 1846 2015-07-01 14:23 tomcat-users.xsd -r--r----- 1 root tomcat 166582 2015-07-01 14:23 web.xml
tomcat-users
mailing list archives dedicated to the perils of running Tomcat as the root
user.
${tomcat_home}/webapps
.ROOT
application is Tomcat's DocumentRoot
and contains the server's main web page. Give thought to the content that is
placed in ROOT/
, as it will be readily available. (Note: if you want to utilize a robots.txt
file to restrict crawler
activity, ROOT/
is the place it will go.)
manager
application is used for remote management of web applications. To use this application, you must add a user with role of
manager-gui
in tomcat-users.xml
. Obviously, if you are not planning to use the manager
application, it should be
removed.
host-manager
application is used for management of virtual hosts. To use this application, you must add a user with role of admin-gui
in tomcat-users.xml
. If you are not planning to do a lot of virtual hosting in Tomcat this application should be removed.
examples
application should probably be removed from a production server to minimize security exposure.docs
are a copy of the Tomcat documentation found online. Unless you have need
for a local copy, removing docs
would help to tidy-up ${tomcat_home}/webapps
.
A realm element represents a "database" of usernames, passwords, and roles (similar to Unix groups) assigned to those users.
Transport Layer Securitytomcat-users.xml
file in
the Tomcat conf/
directory.
server.xml
file in the Tomcat conf/
directory.
A Tomcat Realm represents a "database" of usernames, passwords, and roles assigned to tomcat users.
Realm Name | Purpose |
---|---|
UserDatabaseRealm
|
The UserDatabaseRealm is enabled by default and reads clear text user password information stored in tomcat-users.xml .
|
MemoryRealm
|
The MemoryRealm reads the user password information stored in the tomcat-users.xml in a specified encrypted format.
|
Open the server.xml
with your favorite editor:
$ vi server.xml
Locate the UserDatabaseRealm
(in the LockOutRealm
, right above the Host
element) and comment it out:
<!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <!-- <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> --> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
Now add the following MemoryRealm
information below the commented out UserDatabaseRealm
:
<!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <!-- <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> --> <Realm className="org.apache.catalina.realm.MemoryRealm" digest="SHA" /> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
Tomcat provides a script (${tomcat_home}/bin/digest.sh
) that will encrypt a password string according to the algorithm specified. Use this
script as follows with the password you made for yourself previously:
$ /home/tds/apache-tomcat-8.0.24/bin/digest.sh -a SHA secret secret:e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4
tomcat-users.xml
.Replace your clear-text password in tomcat-users.xml
with the encrypted version:
<tomcat-users> <role rolename="manager-gui"/> <user username="admin" password="e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" roles="manager-gui"/> </tomcat-users>
Since we are using BASIC authentication, you will need to clear any authenticated sessions in your browser to test whether digested passwords have been enabled.
Restart Tomcat and verify digest passwords have been successfully enabled by logging into the Tomcat manager
application using your password
in clear text: http://localhost:8080/manager/html/
tomcat-users.xml
and server.xml
to make sure it is well-formed and without error.tomcat-users.xml
and server.xml
?catalina.out
file in the Tomcat logs/
directory.For more information on how SSL works, Wikipedia details the steps involved during an TSL/SSL transaction.
https
instead of http
.A self-signed certificate says to your users "Trust me - I am who I say I am."
A certificate signed by a CA says, "Trust me - the CA agrees I am who I say I am."
keystore
filekeystore
file stores the details of the TSL/SSL certificate necessary to make the protocol secured.keystore
file for TSL/SSL transactions. Example:<Connector protocol="HTTP/1.1" port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="${user.home}/.keystore" keystorePass="changeit" clientAuth="false" sslProtocol="TLS"/>
Based on what we know about Tomcat configuration, which file in ${tomcat_home}/conf
should we edit to to enable TSL/SSL?
Open ${tomcat_home}/conf/server.xml
with your favorite editor:
$ vi server.xml
Locate the Java HTTP/1.1 Connector
listening on port 8080 and verify it is redirecting TSL/SSL traffic to port 8443:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Find and uncomment the SSL HTTP/1.1 Connector
listening on port 8443 to activate this connector:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />
Add a keystoreFile
attribute to the SSL HTTP/1.1 Connector
to tell Tomcat where to find your keystore:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/home/tds/apache-tomcat-8.0.24/conf/keystore" />
Since we opted to not use the default keystore password
, we need to specify the new password so Tomcat can open the file:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/home/tds/apache-tomcat-8.0.24/conf/keystore" keystorePass="foobar" />
Restart Tomcat:
$ ${tomcat_home}/bin/shutdown.sh $ ${tomcat_home}/bin/startup.sh
Verify Tomcat is listening on port 8443 by running the netstat
command:
$ netstat -an | grep tcp | grep 8443
man netstat
Run man netstat
in your terminal window to learn more about this command.
netstat
(short for network statistics) is available on Unix, Unix-like, and Windows NT-based operating systems. It is a
command-line tool that displays:
Look for the following in the output:
tcp 0 0 :::8443 :::* LISTEN
server.xml
to make sure it is well-formed and without error.key password
) and keystore password
should be the same (changeit
).
If they differ, Tomcat cannot open the keystore and you will get this error: java.io.IOException: Cannot recover key
.
server.xml
?keystore
file in server.xml
?Other than the compelling security reasons, you will want to enable TSL/SSL to take advantage of a couple of monitoring and debugging tools: the TDS Remote Management Tool, and the TdsMonitor Tool -- both of which (out-of-the-box) require TSL/SSL to access.
web.xml
, specifies if all or parts of it need to be accessed via TSL/SSL.WEB-INF
directory of the web application: ${tomcat_home}/webapps/application_name/WEB-INF/web.xml
.
web.xml
from the TDS Remote Management Tool:
<!-- This allows "remote configuration": /thredds/admin/debug gives access to various debug and status info. /thredds/admin/content/ -> "{tomcat_home}/content/thredds/" /thredds/admin/root/ -> "{tomcat_home}/webapps/thredds/" DISABLED /thredds/admin/dataDir/path -> "{dataRoot(path)}/webapps/thredds/" DISABLED --> <security-constraint> <web-resource-collection> <web-resource-name>sensitive read access</web-resource-name> <url-pattern>/admin/*</url-pattern> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>tdsConfig</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
For more information on how to configure security requirements for a web application in a deployment descriptor, see: Defining Security Requirements for Web Applications.
<user-data-constraint>
establishes a requirement that the constrained requests be received over a protected transport layer
connection. This guarantees how the data will be transported between client and server.
<transport-guarantee>
choices for type of transport guarantee include NONE
, INTEGRAL
, and CONFIDENTIAL
:
CONFIDENTIAL
when the application requires that data be transmitted so as to prevent other entities from observing the contents
of the transmission. (E.g., via TSL/SSL.)
INTEGRAL
when the application requires that the data be sent between client and server in such a way that it cannot be changed
in transit.
NONE
to indicate that the container must accept the constrained requests on any connection, including an unprotected one.Other than the compelling security reasons, you will want to enable TSL/SSL to take advantage of a couple of monitoring and debugging tools: the TDS Remote Management Tool, and the TdsMonitor Tool -- both of which (out-of-the-box) require TSL/SSL to access.
If Tomcat has not already been configured to run via TSL/SSL, follow the tutorial in the previous section to Enable TSL/SSL in Tomcat.
${tomcat_home}/conf/tomcat-users.xml
to add the new tdsConfig
and tdsMonitor
roles. Add these roles to your
list of roles:
<tomcat-users> <role rolename="manager-gui"/> <role rolename="tdsConfig"/> <role rolename="tdsMonitor"/> <user username="admin" password="e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" roles="manager-gui,tdsConfig, tdsMonitor"/> </tomcat-users>
manager
Applicationmanager
applicationThe manager
application URLs and roles has been re-structured. See the Tomcat Migration
guide for more information.
${tomcat_home}/webapps/manager
directory.
manager
application to install programs on your server willy-nilly.manager
application, we highly recommend enabling digested passwords and TSL/SSL encryption for the manager
.
manager
application to a small subset of IP addressess or host names using a Tomcat valve, etc., is also a good
idea.
manager
applicationmanager
application.Using your favorite editor, open the deployment descriptor for the Tomcat manager
application:
$ vi ${tomcat_home}/webapps/manager/WEB-INF/web.xml
Locate the <security-constraint>
elements (near the bottom of the file):
<!-- Define a Security Constraint on this Application --> <!-- NOTE: None of these roles are present in the default users file --> <security-constraint> <web-resource-collection> <web-resource-name> HTML Manager interface (for humans) </web-resource-name> <url-pattern>/html/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-gui</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name> Text Manager interface (for scripts) </web-resource-name> <url-pattern>/text/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-script</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>JMX Proxy interface</web-resource-name> <url-pattern>/jmxproxy/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-jmx</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>Status interface</web-resource-name> <url-pattern>/status/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-gui</role-name> <role-name>manager-script</role-name> <role-name>manager-jmx</role-name> <role-name>manager-status</role-name> </auth-constraint> </security-constraint>
The Tomcat 8 version of the manager
application deployment descriptor contains a <security-constraint>
section for each of
the four possible ContactPaths
(as per Manager Application section of the
Tomcat Migration Guide).
Add a <user-data-constraint>
with a <transport-guarantee>
of CONFIDENTIAL
for the desired ContactPaths
to to enable port-forwarding to port 8443:
<!-- Define a Security Constraint on this Application --> <!-- NOTE: None of these roles are present in the default users file --> <security-constraint> <web-resource-collection> <web-resource-name> HTML Manager interface (for humans) </web-resource-name> <url-pattern>/html/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-gui</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name> Text Manager interface (for scripts) </web-resource-name> <url-pattern>/text/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-script</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>JMX Proxy interface</web-resource-name> <url-pattern>/jmxproxy/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-jmx</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>Status interface</web-resource-name> <url-pattern>/status/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>manager-gui</role-name> <role-name>manager-script</role-name> <role-name>manager-jmx</role-name> <role-name>manager-status</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
manager
application.Restart Tomcat and verify TSL/SSL has been enabled for the Tomcat manager
application: http://localhost:8080/manager/html/
web.xml
to make sure it is well-formed and without error. <transport-guarantee>
of CONFIDENTIAL
? web.xml
? manager
application.
manager
application.
manager
application, you must also open up port 8443.A valve element represents a component that will be inserted into the request processing pipeline for the associated Catalina container.
RemoteHostValve
or RemoteAddrValve
to restrict access to the TDS and/or other web applications.conf/server.xml
file.manager
application to limit accessed to it from within a specific IP
address range.
RemoteAddrValve
to restrict access based on IP addresses.<!-- This example denies access based on IP addresses --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="128\.117\.47\.201,128\.107\.157\.210,96\.33\.56\.215" />
RemoteHostValve
to restrict access based on resolved host names.<!-- This example denies access based on host names --> <Valve className="org.apache.catalina.valves.RemoteHostValve" deny="www\.badguys\.com,www\.bandwidthhog\.net" />
<!-- Wildcard characters can with the both valves --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="128\.117\.47\..*" />
RemoteAddrValve
to limit access to a specific range of IP addresses.<!-- This example only allows the specified IPs to access --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="128\.117\.140\..*" />
valve
components available for use.
SHUTDOWN
PortSHUTDOWN
on port 8005SHUTDOWN
command.
${tomcat_home}/conf/server.xml
.