Production Server Overview

Notice: This section is out of date with respect to recent versions of Java and Tomcat

For a more up-to-date version of this content, please follow the TDS 5.0 guide.

What This Section Covers

Best practices and recommendations on securing a production TDS/Tomcat server:

You 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.

Why Is Security Important?

Be afraid

Keeping Software Versions Up-To-Date

Rationale

Resources

Tomcat Process User/Group and ${tomcat_home} Permissions

Rationale

Background info

The 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.

Resources

Removing Unused Web Applications

Rationale

Using Digested Passwords

Rationale

Tomcat Realms

A realm element represents a "database" of usernames, passwords, and roles (similar to Unix groups) assigned to those users.

Transport Layer Security
Configure Tomcat to use digested passwords
  1. First we need to enable digest passwords support in Tomcat by modifying a couple of Tomcat Realms in the server.xml file in the Tomcat conf/ directory.
  2. 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">
    
  3. Create a SHA encrypted version of your password.
  4. 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
    
  5. Update tomcat-users.xml.
  6. 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>
    

    BASIC authentication

    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.

  7. Verify digest passwords have been successfully enabled in Tomcat.
  8. 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/

Troubleshooting

  • Check the XML syntax in tomcat-users.xml and server.xml to make sure it is well-formed and without error.
  • Did you restart Tomcat after you made your changes to tomcat-users.xml and server.xml ?
  • Any errors will be reported in the catalina.out file in the Tomcat logs/ directory.
  • You do not need to type the encrypted version of your password into the browser (the browser auto-magically encrypts your password for you before it transmits it to the server).

Enabling TSL/SSL Encryption

How TSL/SSL works

For more information on how SSL works, Wikipedia details the steps involved during an TSL/SSL transaction.

Rationale

CA-signed Certificates

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."

TSL/SSL certificates

Certificate keystore file

 <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"/>
Enabling TSL/SSL in Tomcat
  1. Modify the Tomcat configuration to enable TSL/SSL:
  2. 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" />
    
  3. Verify TSL/SSL has been enabled.
  4. 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:

    • network connections (both incoming and outgoing)
    • routing tables
    • and a number of network interface statistics

    Look for the following in the output:

    tcp        0      0 :::8443              :::*                  LISTEN
    

    Troubleshooting

    • Check the XML syntax in server.xml to make sure it is well-formed and without error.
    • When generating the self-signed certificate, the last password (the 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.
    • Did you restart Tomcat after you made your changes to server.xml?
    • Did you specify the full path to the keystore file in server.xml?

Configuring web applications for TSL/SSL

Looking Ahead

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.

Resources

Securing the Tomcat manager Application

Changes to the manager application

The manager application URLs and roles has been re-structured. See the Tomcat Migration guide for more information.

Rationale

Enabling TSL/SSL for the Tomcat manager application

  1. Modify the deployment descriptor of the Tomcat manager application.
  2. 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>
  3. Verify TSL/SSL has been enabled for the Tomcat manager application.
  4. Restart Tomcat and verify TSL/SSL has been enabled for the Tomcat manager application: http://localhost:8080/manager/html/

    Tomcat manager authentication prompt

  5. NOTE: You will have to redo this every time you upgrade Tomcat.

Troubleshooting

  • Check the XML syntax in web.xml to make sure it is well-formed and without error.
  • Did you specify a <transport-guarantee> of CONFIDENTIAL?
  • Did you restart Tomcat after you made your changes to web.xml?

Resources

Blocking Non-Essential Port Access At The Firewall

Rationale

For running the TDS, keep in mind the following:

Resources

Restricting Access To The TDS By Remote IP Address Or Host

Rationale

Tomcat Valves

A valve element represents a component that will be inserted into the request processing pipeline for the associated Catalina container.

Examples

  1. Using the RemoteAddrValve to restrict access based on IP addresses.
  2. <!-- 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" />
    
  3. Using the RemoteHostValve to restrict access based on resolved host names.
  4. <!-- This example denies access based on host names -->
    <Valve className="org.apache.catalina.valves.RemoteHostValve"
               deny="www\.badguys\.com,www\.bandwidthhog\.net" />
    
  5. Using wildcard characters.
  6. <!-- Wildcard characters can with the both valves -->
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           deny="128\.117\.47\..*" />
    
  7. Using the RemoteAddrValve to limit access to a specific range of IP addresses.
  8. <!-- This example only allows the specified IPs to access  -->
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
              allow="128\.117\.140\..*" />
    

Resources

Reverse Proxy

Rationale

Resources

Running Tomcat with a Security Manager

Rationale

Resources

Protecting the Tomcat SHUTDOWN Port

SHUTDOWN on port 8005