Article Listing 1 Listing 2 Listing 3 Listing 4 jan2006.tar

SELinux, Apache, and Tomcat -- A Securely Implemented Web Application Server

Russ McRee

As an enterprise strives to grow its online presence, its exposure to risk grows as Web applications are added. Thus, a secure as well as highly available Web application server becomes critical to help enterprises mitigate some of that risk. Although no implementation offers perfect security, administrators can take a number of steps to dramatically improve the security of their Web app servers.

This article describes methodology to build a secure Web application server utilizing the benefits of SELinux with a Fedora Core 4 distribution, along with the Apache httpd server and Apache-Tomcat communicating via mod_jk. Additionally, the use of iptables, mod_rewrite, and mod_security will be discussed. In this article, I will not cover SELinux or the modules utilized in detail; those topics are worthy of articles in and of themselves. Rather, I will present a server that I believe you can be comfortable with for public facing apps (assuming the apps are also well written).

You may have discovered that the documentation for implementing Apache's httpd and Tomcat servers is vast, but each reference typically encompasses individual services rather than implementing them holistically with security at the forefront. I will strive to describe a start-to-finish process to roll a well-secured Web app server that also offers user authentication and SSL options through the Apache Web server.

I'll make some assumptions for brevity's sake. First, we only have one server, and we're on a tight budget. Second, Fedora Core installations are straightforward and offer little challenge for most Linux users, so I'll describe only some key points in the install phase to ensure a more secure implementation. Third, I assume the reader has a reasonable understanding of the Apache Web server and its available modules, as well as managing iptables, and working with Apache-Tomcat. Finally, I assume that the basic principles of secure systems administration are also comfortable subject matter.

SELinux is now innate in Fedora Core distributions and offers some excellent protections as, according to Wikipedia, "a version of the Linux kernel and utilities, which contains support for mandatory access controls based on the principle of least privilege. Primarily developed by the U.S. National Security Agency (NSA) it was released to the open source development community." Iptables is also a default offering in Fedora Core distributions, allowing you to limit network traffic only to those ports and services you deem entirely necessary.

OS Installation

As you begin your installation from Fedora Core 4 media (assuming a clean install rather than an upgrade), follow the configuration process using default settings or those of your choice until you reach the Installation Type window. It is essential to choose Custom here. Resume defaults or personal settings until you reach the Firewall Configuration window. In this step, be certain to choose Enable firewall (default), check Web Server (HTTP, HTTPS) and Remote Login (SSH), and ensure SELinux is set to Active. You'll work through two more windows then arrive at the Package Group Selection window. Here you'll uncheck all options accept Minimal (very last check box at bottom of list).

The initial intent is to install nothing that is not required except basic OS functionality. You'll soon see, though, that one of the drawbacks of Fedora Core distributions is that, even when the bare minimum is chosen, you will find a plethora of packages that serve no purpose on a hardened system. Reboot as prompted when the OS installation completes and log back on as root.

Here's where we start to clean house. Using rpm, we'll remove all the clutter that doesn't belong on a public-facing server. You'll note tools for bind, sendmail, printer libraries (cups), and a number of x11 libraries, even though we didn't install them. The gathering in Listing 1 can be executed in one fell swoop at the command line, ensuring that you maintain a single space between each package name, or the listing can be copied to the buffer if you download it from the Sys Admin Web site. You may find other unnecessary packages that you want to remove, but experiment carefully and understand the dependencies.

At this point, it is best to turn off the sendmail daemon. This is most easily done by editing /etc/sysconfig/sendmail and setting DAEMON=no. For an extensive methodology review of sendmail security, see:

http://www.deer-run.com/~hal/sysadmin/sendmail.html
Next, set up yum (Yellow dog Updater, Modified) to be sure that the system only draws package updates from the base and update repositories and leaves development, testing, and extras off your production Web app server. Execute as follows:

rm -f /etc/yum.repos.d/fedora-extras.repo
rm -f /etc/yum.repos.d/fedora-extras-devel.repo
rm -f /etc/yum.repos.d/fedora-devel.repo
rm -f /etc/yum.repos.d/fedora-updates-testing.repo
Then run yum update to bring the system packages up to date. Likely, this will update the kernel to one more current, so reboot to take advantage of it.

I prefer yum from an ease of use perspective because it requires only /etc/yum.conf and the /etc/yum.repos.d directory to manage packages. Some may note that rollback functionality does not exist in yum, but all indicators show that rollbacks are obsolesced and are not part of the rpm's future.

Install httpd

Log back in as root and install the Web server with yum install httpd. If you want to take advantage of SSL, then also issue yum install mod_ssl. Start thinking here about how you intend to use Apache. If your intent is purely to forward requests to Tomcat, then you can really ratchet down httpd.conf. I've included a copy of just such an httpd.conf later in the article as Listing 3.

Add Tomcat User

At this point, you should build an account under which to run Tomcat. Running a server like Tomcat under root is certainly unnecessary and not recommended. First, do groupadd <user> where <user> is an account name you choose. Second, issue useradd <user> -g <user> -d /home/<user>, and third do passwd <user>.

Repeat these steps for a general user for administration. Later, I will show how to harden SSH access, which will prevent ssh logon as root. Thus, an additional user will be required to su or sudo root commands.

Add Packages

The next step is to build a staging directory for packages that you'll need. As an example, do: mkdir /staging. You'll need some packages to complete this platform:

1. Apache-Tomcat 5.5.12 from:

http://tomcat.apache.org/download-55.cgi
2. mod_jk-ap20-1.2.14.1-1jpp.i386.rpm and mod_security-1.8.7.fc4.i386.rpm from:

http://rpm.pbone.net
3. jre-1_5_0_05-linux-i586-rpm.bin from:

http://java.com/en/download/manual.jsp
You can download these rpms on your admin workstation and copy them to CD or USB drive, transfer them over SSH with gftp or WinSCP, or simply wget them from the server you're building. Regardless, ensure they're all in your staging directory then cd to it.

Install the modules first:

rpm -Uvh mod_jk-ap20-1.2.14.1-1jpp.i386.rpm mod_security-1.8.7. fc4.i386.rpm
Install the JRE:

sh jre-1_5_0_05-linux-i586-rpm.bin
This will install the JRE in /usr/java.

Install Tomcat

Finally, install Tomcat. Copy Apache-Tomcat-5.5.12.tar.gz from /staging to /usr/share (or a directory of your choosing):

cp apache-tomcat-5.5.12.tar.gz /usr/share
cd /usr/share
tar -zxvf apache-tomcat-5.5.12.tar.gz
rm -f apache-tomcat-5.5.12.tar.gz
Grant permission to <user> (the Tomcat user you created earlier) to all tomcat directories:

chown -R <user>:<user> /usr/share/apache-tomcat-5.5.12 then logout.
Log back in as <user> and vi .bash_profile to make some key changes to the user's environment variables. Add :/usr/java/jre1.5.0_05/bin to the PATH reference, add JAVA_HOME=/usr/java/jre1.5.0_05 after the PATH reference, and add JAVA_HOME to the export reference after PATH. Log out, then back in as <user> and build a couple of quick convenience scripts.

Next, do mkdir /home/<user>/bin, as it is already referenced in the <user> path, then cd /home/<user>/bin. You'll make tcatup and tcatdown here for quick start and stop of the Tomcat server. Create tcatup with vi tcatup and enter two lines:

cd /usr/share/apache-tomcat-5.5.12/bin
 ./startup.sh
Tcatdown will be identical with the exception of ./shutdown.sh. Be sure to chmod a+x to make these scripts executable.

The next step is to clean up the default Tomcat installation. Do:

cd /usr/share/apache-tomcat-5.5.12/conf
then rename or delete tomcat-users.xml, as it is not required. Delete manager and host-manager from usr/share/apache-tomcat-5.5.12/server/webapps.

From /usr/share/apache-tomcat-5.5.12/bin, do: rm-rf *.exe and rm -rf *.bat. No need for Windows files on a Linux server.

Finally, from /usr/share/apache-tomcat-5.5.12/webapps, remove all the example directories such as jsp-examples, balancer, tomcat-docs, etc., as well as ROOT.

Configure mod_jk

Mod_jk is next and requires little more that the minimal setup described in Apache's documentation. You can build far more complex configurations with help from a plethora of available documentation. Listing 2 is taken directly from:

http://jakarta.apache.org/tomcat/connectors-doc/howto/quick.html
Create Listing 2 as workers.properties in /etc/httpd/conf.

httpd.conf Including mod_rewrite, mod_security, and mod_jk

For a recent implementation similar to what this article describes, Apache was only used to forward to Tomcat and served no other Web sites. Therefore, in my httpd.conf, I removed the vast majority of Section 2, including all references to DocumentRoot and its associated directory, UserDir, DirectoryIndex, Alias, ScriptAlias, WebDAV, Icons, cgi, AddLanguage, Error (handled by my app), and Proxy. Additionally, I deleted entire LoadModule references for modules I didn't want loaded, such as mod_proxy, mod_userdir, etc. We really only have heavy dependencies on mod-jk, mod_security, mod_auth, mod_rewrite, and a few others for this implementation. This may all seem a bit draconian, but the intent here is to strip the entire process down only to that which is explicitly required.

mod_rewrite -- You can deter TRACE using mod_rewrite as well. I list mod_rewrite configurations before mod_security in my httpd.conf. See Listing 3.

mod_security -- We've finally reached my favorite tool in this server setup, namely mod_security. If you want a great read on mod_security, see Shreeraj Shah's article, "Defending Web Services using mod_security", which says: "ModSecurity is an open source intrusion detection and prevention engine for Web applications (or a Web application firewall). Operating as an Apache Web server module or standalone, the purpose of ModSecurity is to increase Web application security, protecting Web applications from known and unknown attacks."

The benefit of this module is obvious from its description. Imagine filtering SQL injection or XSS strings right in httpd.conf. I list my mod_security configurations before mod_jk configurations in my httpd.conf. I put the mod_security section before the mod_jk configurations described in Listing 3.

The mod_security section in Listing 3 is compiled of various examples and is by no means comprehensive, nor are these the only options available to you. You can and should experiment with adding SecFilter references for your needs by testing your site before final deployment using nikto from cirt.net or nessus.

mod_jk -- Included in this httpd.conf is the required mod_jk section. I've commented out loading the module here because you should load it with other modules in the modules section of httpd.conf. Note that you should load mod_jk before mod_rewrite. Use JkMount to name the directory for the Web app you've placed in /usr/share/apache-tomcat-5.5.12/webapps. Use JkUnMount to prevent enumeration of files you do not want to be rendered directly. This functionality is only available in mod-jk-1.2.7 or later.

Note that you must issue a policy directive to SELinux specifically for httpd because SELinux in Fedora Core 4 blocks mod_jk by default unless you enable it by executing the following at a root prompt:

setsebool httpd_can_network_connect=1
Also be sure you are running selinux-policy-targeted-1.25.1-7 or later.

User Authentication

It seems that mod-jk with Apache and Tomcat requires utilizing Apache-based user authentication. There are additionally confusing search references that indicate .htaccess (mod_auth) will not work with mod_jk. The following works quite successfully, however. As root, do:

mkdir /usr/share/access
Following the htpasswd command syntax, issue:

htpasswd -c /usr/share/access/.authenticated <username>
to create .authenticated. To add users after the initial file creation, issue:

htpasswd /usr/share/access/.authenticated <username2>
You can build on this with digest authentication or LDAP, but for our purposes we'll keep it simple. See the Authenticate Users entry right before Section 3 in httpd.conf (see Listing 3).

Restart the Web server with service httpd restart and start a new browser session. You should be prompted for a username and password. Ensure that principal names are being successfully passed between Apache and Tomcat via mod_jk. For mod_jk, tomcatAuthentication="false" should be present in the <Ajp13Connector> configuration element in /usr/share/apache-tomcat-5.5.12/conf/server.xml to ensure that the user's identity is passed from Apache to the servlet environment.

Harden SSH and Modify iptables

This is ideally performed last, after configuration is complete, because you might be building via ssh and initially want to establish a root shell without using su or sudo. You should also make these changes logged into the server at the local console, rather than remotely as you will need to modify your iptables configuration. <your port> represents an unused port number of your choosing. Assuming you allow only port 80 or 443 to your server in your DMZ, you'll likely only use SSH over the port you assign from your internal network.

Edit /etc/ssh/sshd-conf

1. Uncomment Protocol 2 (accepts ssh2 only).

2. Uncomment Port 22 and change 22 to <your port> (modifies the ssh port for obfuscation purposes).

3. Uncomment LoginGraceTime.

4. Uncomment PermitRootLogin and change yes to no (prevents attempts to remotely brute-force the server as root). If root is needed while administering via ssh, utilize su or sudo.

5. Uncomment StrictModes.

6. Uncomment MaxAuthTries and change 6 to 3 (limits logon attempts to 3).

Iptables

Iptables, as configured automatically during the OS setup, is set to allow traffic over port 80 and the default SSH port 22. Iptables must be modified to allow <your port> rather than 22:

cd /etc/sysconfig/iptables
Edit the line allowing 22 to <your port>; save and exit. Then issue service iptables restart. Listing 4 offers an example.

Troubleshooting

If you're having trouble pulling up your Web app through Apache after this, consider the following:

  • SELinux policies can factor in the server's availability. As root, turn off SELinux policy enforcement by issuing: setenforce 0.
  • setenforce 1 will restart SELinux enforcement. The status of SELinux enforcement can be checked by issuing: sestatus | grep -i mode.
  • Iptables might factor as well. To be sure your iptables rules aren't working against you, issue: service iptables stop.
  • Check /etc/sysconfig/iptables to see what may be the cause. If it seems as if file permissions issues are causing problems, issue the following:

    chmod -R 755 /usr/share/apache-tomcat-5.5.12
    
    Reduce these rights after you've solved the problem and retest. Also issue:

    chown -R tomcat:tomcat /usr/share/apache-tomcat-5.5.12
    

SSL

As you've probably spent a good deal of time with Apache, you are likely capable of configuring SSL. However, if not, you can do so by following Apache's documents or those at:

http://www.linux-sxs.org/internet_serving/apache2.html
Summary

In this article, I haven't really blazed any new trails; I've simply merged those blazed previously. I have shown, however, how to build a server that provides some sense of comfort in a savage environment. In utilizing SELinux, deploying key Apache modules, activating iptables, removing unnecessary fluff from the OS and our configurations, and applying some basic good sense, I've presented steps that can be taken to provide Web applications with a safe home. It is my hope that your Web apps live a long and peaceful life. Just remember to check the code, too, and test, test, test.

Acknowledgements

Thanks to Ken Van Eyk for his extensive Java knowledge and for driving the project that led to this article. Thanks to the SMC team and my family for their endless support.

Resources

Apache HTTP server -- http://httpd.apache.org/

Fedora Core 4 -- http://fedora.redhat.com/

Modsecurity -- http://modsecurity.org

SELinux -- http://www.nsa.gov/selinux/index.cfm

Shah, Shreeraj. "Defending Web Services using mod_security" -- http://www.infosecwriters.com/text_resources/pdf/Defending-web-services.pdf

Tomcat -- http://tomcat.apache.org/

Russ McRee is an Information Security Architect for the Municipal Court of Seattle. He can be reached at: holisticinfosec@gmail.com or holisticinfosec.org.