Tuesday, June 2, 2009

Open Source Application Layer Firewall part 4

Picking up where we left off on this whole firewall thing, let's get into the Apache config. In part 1 we talked about why we need an application layer firewall and how it is more secure than a stateful inspection firewall. In part 2 we set up our server that needs protecting, and in part 3 we created a basic stateful inspection firewall to protect our application. The stateful firewall isn't allowing any traffic into our server though. Now we're going to open a hole to the server that needs protecting and use the proxy services built into OpenBSD to create a proxy firewall.

One of the most beautiful things about using OpenBSD for our firewall OS is that it comes already setup with Apache in a chroot jail. That means that if an attacker were somehow able to compromise the httpd process that person will not own the whole firewall. It can be very difficult to set up Apache in a chroot jail, and it can be difficult to work with Apache once it is in the chroot jail. The good news is that OpenBSD has done a lot of the work for us.

The first thing we need to do is set up our SSL keys for this server. I'm going to follow the same instructions I did in part 2 to create a self signed ssl certificate, and I'm going to name the certificate after the public IP address that I want clients to connect to.

Now we have to edit the configuration file for our chrooted apache installation, which is in /var/www/conf/httpd.conf. The file is broken into several sections:
Section 1 - Global environment.
Uncomment line 273: LoadModule proxy_module /usr/lib/apache/modules/libproxy.so
Section 2 - Main Server Configuration
Comment out line 310: #Port 80.

The first change was necessary so that our proxy server stuff would work. I commented out line 310 because we're going to use listen statements later in the configuration file to control which port the servers are running on. Most of the work is going to happen in section 3, Virtual Hosts.
Section 3 - Virtual Hosts
At the start of this section there are some comments. Immediatly after those comments I put in the two virtual hosts that I want to set up on this box. One will accept unencrypted communication on port 80 and proxy them to our server. The configuration for that looks like this:
<virtualhost 111.11.11.111:80>
ProxyRequests off
ProxyPass / http://192.168.1.10/
proxyPassReverse / http://192.168.1.10/
</virtualhost>

The second virtual host listens on port 443 and proxies traffic to the same server on an encrypted channel
<virtualhost 111.11.11.111:443>
SSLEngine on
SSLCertificateFile /etc/ssl/111.11.11.111.crt
SSLCertificateKeyFile /etc/ssl/private/111.11.11.111.key
ProxyRequests off
ProxyPass / https://192.168.1.10/
ProxyPassReverse / https://192.168.1.10/
</virtualhost>
After I put those lines in, I deleted everything in the section on SSL Virtual Host Context (which started on line 1013), but kept the SSL Global Context Section (which started on line 954).

The SSL Global Context, and the stuff in Sections 1 and 2 give us pretty safe configuration templates for our server to run with. Then we removed the default virtual hosts that come in the file (the ones that listen on all ip addresses) and replaced them with two specific virtual hosts. Each one listens on a specific port on a specific IP address. That way if you need to have services for more than one back-end server, you can easily cut and paste the configuration that you have for this one. Now let's test and see if our configuration file passes the smell test.
# apachectl configtest.

If we don't get any errors, then we can start up our httpd server with SSL support. It's pretty easy to do.
# apachectl startssl (or you can use # httpd -DSSL)

Now if that started properly, we should set up our server so that it will start up every time it boots up. Go ahead and edit /etc/rc.conf and change the line that read httpd_flags=NO to read httpd_flags="-DSSL"

It isn't quite working yet, though. Sure we have a listening process on port 80 and 443 that will forward traffic to our back end server, but we're getting blocked at layers 3 and 4. We need to open up this traffic in pf. So add this to the bottom of your /etc/pf.conf file

# This rule allows http(s) in to our server
pass in log on $ext_if proto tcp from any to 111.11.11.111 port 80
pass in log on $ext_if proto tcp from any to 111.11.11.111 port 443


Then reset your pf rules with this:
# pfctl -F rules -f /etc/pf.conf

Now direct your browser to the external address that you're listening on and see if you get the web page being served up by your back end server. If so, then congratulations, you now have a Proxy Firewall.

In the next entry we'll talk about mod_security and how you can turn your proxy firewall into an honest to goodness Application Layer Firewall.

No comments: