3cx.static

 HOWTO: OWA 2K/2K3 Front-end SSL Proxy with Apache 2.0

Category: General
Last update: Thurs Jul 21, 2005

NOTE: I simply cannot respond to the amount of email I am receiving regarding this. Please do not take it personally if I ignore you. Thanks. For assistance, I suggest hitting the newsgroups or the comments following this HOWTO.

This HOWTO was adapted from an earlier version that covered Apache 1.3. If you're looking for that, it can be found here [http://3cx.org/item/38].

Keywords: outlook web access, OWA, front-end-https, proxy, libproxy.so, protect OWA, front-end-proxy, header, SSL, front, end, mod_proxy, apache, 2000, 2003, NT, windows

[I have successfully implemented this solution with SSL-aware Apache 2.0.46 on Debian Sarge and Redhat Enterprise Linux 3.1. This "HOWTO" does not cover setting up an OWA or SSL-aware Apache server. That's up to you. Sorry.]

Outlook Web Access 2000 and 2003 (OWA) runs on Microsoft's Internet Information Service (IIS). IIS is considered by many to be the swiss cheese of web servers (and I agree with this... sort of). I would never consider putting an IIS box on a publicly accessible network simply because it's just too much work to secure.

The point of having an OWA server is moot if one is not willing to allow access to it from the world. So, we need to somehow make the OWA service publicly accessible while not actually making the box itself publicly accessible (hopefully that makes sense. ;-). The answer? Proxy incoming requests with something a little more secure - namely Apache. Apache comes with a nice proxy module called mod_proxy. It does everything we need.


         INTERNET      +--------------+
            |          | APACHE PROXY |
            |          +--------------+
       +----------+           |
       | FIREWALL |------------------
       +----------+     Service net
            |
            |
                      +------------+
         Int Net -----| OWA SERVER |
                      +------------+

Remote users want to access OWA. They type https://webmail.somedomain.com into their browser. Their workstation/laptop then asks their DNS for the IP address of webmail.somedomain.com. The DNS replies with the IP address of the APACHE PROXY. The browser then connects to the proxy and sends its request. The APACHE PROXY then connects to the the internal OWA SERVER and requests the objects on behalf of the remote user. Simple enough.

Be aware that in this example, the Apache "proxy" is on a locked down service network. Nothing gets in or out of this net unless it is required. For the Apache "proxy", connection requests destined for port 443 (https) are allowed through the firewall from the world. Connection requests from the Apache "proxy" are allowed through to destination port 443 on the internal OWA server. That's it. If the Apache "proxy" generates any traffic other than that, alarms go off (i.e. WARNING! WARNING! You may be 0wn3d!). I highly recommend this configuration for all pubicly accessible services.

Now, to make this bit of magic work, we need to do several things.

  1. Configure Apache to use the mod_proxy modules.
  2. Add a RequestHeader and several ProxyPass configuration directives to the Apache config file.
  3. Add an entry to the Apache server's /etc/hosts file.

1. Configure Apache to use the mod_proxy modules.

Ensure Apache's configuration file (httpd.conf) includes the following lines.

LoadModule proxy_module <path to modules dir>/mod_proxy.so
LoadModule proxy_http_module <path to modules dir>/mod_proxy_http.so
LoadModule proxy_connect_module <path to modules dir>/mod_proxy_connect.so

NOTE: If mod_proxy is not part of your distribution's Apache package or you did not compile Apache with the mod_proxy option turned on, httpd may not start (it'll probably only complain).


2. Add a RequestHeader and these ProxyPass configuration directives to your Apache config file. You may place them in the main section of the config or in a VirtualHost section. It all depends how you have your server configured. I've done it in both and either will work.

RequestHeader set Front-End-Https "On"

ProxyPass /exchange http://webmail.somedomain.com/exchange/
ProxyPassReverse /exchange http://webmail.somedomain.com/exchange/
ProxyPass /exchweb http://webmail.somedomain.com/exchweb/

ProxyPassReverse /exchweb http://webmail.somedomain.com/exchweb/
ProxyPass /public http://webmail.somedomain.com/public/
ProxyPassReverse /public http://webmail.somedomain.com/public/
ProxyPass /iisadmpwd http://webmail.somedomain.com/iisadmpwd/
ProxyPassReverse /iisadmpwd http://webmail.somedomain.com/iisadmpwd/
CacheDisable *


3. And finally add an entry to the Apache server's /etc/hosts file.

You may notice the ProxyPass directives redirect several directories to webmail.somedomain.com. But how can we redirect to webmail.somedomain.com if the Apache server is webmail.somedomain.com? We need to add an entry to the /etc/hosts file pointing webmail.somedomain.com to the internal OWA IP address.

192.168.0.100		webmail.somedomain.com

Be sure your server is configured to look in your hosts file before consulting the DNS. Check your /etc/host.conf file to make sure. It should read like this.

order hosts, bind
multi on

Now start Apache. Watch your logs for any errors. Make sure the appropriate access is configured through your firewall (world --> proxy dst tcp 443 and proxy --> internal OWA server dst tcp 443). Also remember to watch the logs on your internal OWA server.

Some things to watch include


If you try implementing this and have problems or (sorry -- I'm bombarded with questions) have something you think I should add (or modify) to these instructions, feel free to contact me at mikeg@3cx.org.


When I implemented this, I ran into a nasty bug. Exchange, for some strange reason, looks up each email using the subject line (as opposed to say... THE FRIGGIN UNIQUE IDENTIFIER!). That means the email subject is part of the URL. If a percent symbol (%) is in the subject line of the requested email, Apache will complain that it cannot find the URL. This has to do with the way mod_proxy does encoding/decoding of URI escape sequences.

By using the following mod_rewrite rules and a simple bash script, one can easily work around this problem.

Insert this right before your "front-end" Proxy* directives in httpd.conf.

# Using mod_rewrite to fix a problem when percent symbols are in
# the subject line of the OWA email (the email subject is used
# in the web query - WTF?). The entire URI is passed to a small
# bash script I wrote that replaces all occurrences of the % symbol
# with the URI escape sequence (%25). That seems to make everything
# happy.
RewriteEngine On
RewriteMap damnpercent prg:/usr/local/bin/percent_rewrite
RewriteCond $1 ^/exchange/.*\%.*$
RewriteRule (/exchange/.*) ${damnpercent:$1} [P]

The simple bash script uses sed to work its magic. You'll notice I am also sending the original and changed URL to a log file in /tmp. This helps with troubleshooting and can be shut off when you're confidant everything is working. (This could easily be rewritten in any language.)

#!/bin/bash

LOGFILE=/tmp/percent_rewrite.log
cat /dev/null > $LOGFILE

while read URL
do
NEWURL=$(echo "$URL" | sed -e "s/%/%25/g")
echo "Changing $URL to $NEWURL" >> $LOGFILE
echo $NEWURL

done

Keep in mind that this script only works if you implemented my solution exactly as I have. A man from Germany tried a modified solution, but could never get the percent rewrite to function properly. He used the ProxyPreserveHost directive, which I do not. By using this directive, you can dispense with the /etc/hosts hack and use the real OWA hostname in the ProxyPass directives (but not the ProxyPassReverse directives). I tried this and it works wonderfully... except for the percent symbol problem. I never could get the rewrite to work with the ProxyPreserveHost setup. I suspect this is due to my lack of understanding of the inner workings of both Apache's proxy subsystem and mod_rewrite.



Outlook RPC over HTTP with Apache 2.0

Simon Blackstein returned and added an excellent comment about Outlook RPC over HTTP via Apache 2.0 proxying to this post (http://3cx.org/item/35). He says he still has a few minor issues, but I believe he'll work them out. Hopefully he'll report back here with any "fixes".

Here is his comment in full (with a few minor changes only to assist my HTMLization).

Simon wrote:

OK, so I'm still having a few funny issues with this config, as opposed to opening 80/443 directly to Exchange *shudder*.

BTW, this is very similar to proxying OWA really. A couple of other things involved. Like most people probably checking out this article, I only have a single Win2k3/Exch SP1 back-end server and an Apache reverse-proxy.

  1. Check Q-article 833401 (http://support.microsoft.co...) to configure your Exchange server as a backend. Basically follow these instructions in the doc:-
    1. Install the RPCProxy using 'Add/Remove Programs'. BTW, do make sure you reapply Win2k3 SP1 after installing this if you get the RTM version. This installs two virtual directories - /rpc and /rpcwithcert.
    2. Configure correct permissions on the /rpc virtual directory (don't require SSL, you'll see why in a sec)
    3. Hard-code the ports to communicate with the GC with the "ValidPorts" registry value using the Exchange server name
    4. Hard-code proxy communications on all GCs by configuring the "NSPI interface protocol sequences" registry key
  2. OK, before all of the testing stuff with Outlook, there is an important step they don't mention if you have a proxy. You want the proxy to terminate the SSL and communicate 80 back to the Exchange server, right? Well, you have to tell RPC to accept port 80 unencrypted traffic. Check the following article to see how that's done, they call it SSL offloading (whateva):

    http://www.microsoft.com/te...

  3. Now, here's my httpd config to check out. You'll see stuff which I'm sure true Apache gurus will cringe at, but adapt to your own setup accordingly. Put your cert on the Apache box, obviously, and serve on 443. You'll find my OWA proxy settings and a nice redirect from 80 -> 443 in there too:

    <VirtualHost ***IP_that_you're_serving_on***:80>
    DocumentRoot "/var/www/proxy_dir"
    ServerName ***URL***
    Redirect / https://***URL***/exchange
    ErrorLog /var/www/proxy_dir/logs/error_log
    LogLevel emerg
    TransferLog /var/www/proxy_dir/logs/access_log
    </VirtualHost>

    <IfModule mod_ssl.c>
    SSLRandomSeed startup builtin
    SSLRandomSeed connect builtin

    <IfDefine SSL>
    Listen 443
    AddType application/x-x509-ca-cert .crt
    AddType application/x-pkcs7-crl .crl
    SSLPassPhraseDialog builtin
    SSLSessionCache dbm:/usr/local/apache/logs/ssl_scache
    SSLSessionCacheTimeout 300
    SSLMutex file:/usr/local/apache/logs/ssl_mutex

    <VirtualHost ***IP_that_you're_serving_on***:443>

    DocumentRoot "/usr/local/apache/htdocs"
    ServerName ***URL***:443
    ErrorLog /usr/local/apache/logs/error_log
    TransferLog /usr/local/apache/logs/access_log
    RequestHeader set Front-End-Https "On"
    SSLEngine on
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
    SSLCertificateFile /usr/local/apache/conf/ssl/server.crt
    SSLCertificateKeyFile /usr/local/apache/conf/ssl/server.key
    ProxyRequests off
    ProxyPreserveHost On
    <Location /exchange>
    ProxyPass http://***address_of_Exchange_server***/exchange
    ProxyPassReverse http://***address_of_Exchange_server***/exchange
    SSLRequireSSL
    </Location>
    <Location /exchweb>
    ProxyPass http://***address_of_Exchange_server***/exchweb
    ProxyPassReverse http://***address_of_Exchange_server***/exchweb
    SSLRequireSSL
    </Location>
    <Location /public>
    ProxyPass http://***address_of_Exchange_server***/public
    ProxyPassReverse http://***address_of_Exchange_server***/public
    SSLRequireSSL
    </Location>
    <Location /rpc>
    ProxyPass http://***address_of_Exchange_server***/rpc
    ProxyPassReverse http://***address_of_Exchange_server***/rpc
    SSLRequireSSL
    </Location>
    <Location />
    ProxyPass http://***address_of_Exchange_server***/
    ProxyPassReverse http://***address_of_Exchange_server***/
    SSLRequireSSL
    </Location>
    <Files ~ "\.(cgi|shtml|phtml|php3?)$">
    SSLOptions +StdEnvVars
    </Files>
    <Directory "/usr/local/apache/cgi-bin">
    SSLOptions +StdEnvVars
    </Directory>

    SetEnvIf User-Agent ".*MSIE.*" \
    nokeepalive ssl-unclean-shutdown \
    downgrade-1.0 force-response-1.0

    CustomLog /usr/local/apache/logs/ssl_request_log \
    "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    </VirtualHost>
    </IfDefine>
    </IfModule>

  4. Test it out! Run the Outlook /rpcdiag deal to get a nice interface to figure out what might be wrong, and check the Apache SSL logs for any funny errors. Oh, and make sure URLScan, if you have it installed, is not blocking anything it shouldn't.

Again, sometimes you do get some funny pauses happening, especially if you're on a shady connection. If anyone can find any way to make this more stable - I've been looking at the disable-cache thing potentially solving that - let me know.

Rgds,

Simon Blackstein

Tue 26 Jul 12:47:48 JST 2005
Thu 23 Jun 14:08:56 PDT 2005 - mikeg - permalink - 81 comments


© 2002-2007 Michael Gauthier
Bother the webmaster at webmaster@3cx.org.


Our VPS Hosting
by RimuHosting
Java and Linux VPS Hosting by RimuHosting

Real Ultimate Power!

[QUIT SLASHDOT TODAY]