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