Table of Contents
Apache Reverse Proxy
This is an overall page for an Apache reverse proxy, including installation, configuration, security and cache.
Hardware Configuration
The reverse proxy in my case is a virtual. It will have three NICs, one for the outside, one for the inside and one in the management VLAN. During initial installation, we only use one NIC, the one on the outside. Later on we'll add the other NICs.
- VM NAME: SLES11-REVERSEPROXY
- CPU: 1
- MEM: 1024 MB
- DSK: 8 GB
- NIC: VMXNET3
- Extern IP: 10.10.10.20
- VLAN: 10
- Intern IP: 10.10.12.120
- VLAN: 12
- Mgmt IP: 10.10.253.120
- VLAN: 253
Installation Report
Installation media: sles11 sp1 for vmware, 64 bits
Installation setup
- Language: English US
- Keyboard: English US
- Type installation: New Install
- Time and Timezone: Hardware Clock not set to local time - Europe - Netherlands
Partitioning
/dev/sda1 swap 1 GB /dev/sda2 / ext3 7 GB - No Access Time
Software Selectie
- Pattern:
- Base System
- 32 bits runtime environment
- Minimal System (Appliance) - could not be unselected
- Graphical Environments
- Gnome Desktop Environment for Server
- X Window System
- Development
- C/C++ Compiler and Tools
Note: I want to set runlevel 3 as the default runlevel but because I'm installing over VNC I won't do that untill after the installation.
Configuration
- Root password: T-password
- Hostname: reverseproxy.getshifting.local
- IP-adres: 10.10.10.20
- Subnet Mask: 255.255.255.0
- Gateway: 10.10.10.1
- DNS server: 10.10.12.53
- IPv6 Disabled
- Firewall Enabled
- SSH Port Opened
- Remote Administration Enabled
- No Proxy Configured
- Not registered at Novell Customer Center
- CA configuration left at default
- No OpenLDAP
- Local Authentication
- No extra accounts
Post install adjustments
- Set the runlevel to 3
- Disable Remote Administration (VNC)
Reboot the box to commit all changes.
Configure NTP
- /etc/ntp.conf:
server 10.10.12.123 prefer tinker step 0
LDAP Authentication
Set up LDAP Authentication as described in AD LDAP For Linux
Sudo Changes
Set up sudo as described in Sudo
For monitoring purposes and the automatic switching between “Production” and “Outage” we need some additional lines:
# Command Alias Cmnd_Alias MON = /bin/mv, /etc/init.d/apache2 reload
and
# User privilege specification monuser ALL=(root) NOPASSWD: MON
Email Setup
Configure email
Change these lines in the /etc/postfix/main.cf file:
#myhostname = reverseproxy.getshifting.local myhostname = getshifting.com relayhost = mail.getshifting.local
Note: myhostname should be a real domain name if the relay server checks for domain names
* Restart postfix: /etc/init.d/postfix restart
- Add .forward files in homedirs of root and monuser to sjoerd_getshifting_com
Monitoring
Add the server to your
- syslog
- application monitoring
DNS
Add the server to your DNS server with the correct DNS and reverse DNS records
Apache Reverse Proxy
Apache Installation
Install apache through yast:
- Start /sbin/yast2
- Go to Software → Software Management
- Search for apache
- Select Apache2
- Accept all dependencies
Basic Configuration
- Start yast
- Go to network services
- Select the “HTTP Server”
- Enter port 443 and only listen on interface 10.10.10.20
- Checkmark the box to “Open Port in Firewall”
- Do not enable any of the listed scripting languages
- Keep all of the other defaults
After going through the wizard, open “HTTP Server” again and enable these “Server Modules”:
- proxy
- Proxy_connect
- proxy_http
- rewrite
listen.conf
Only this:
sjoerd@reverseproxy:/etc/apache2> cat listen.conf | grep -v '^#' | grep -v '^$' <IfDefine SSL> <IfDefine !NOSSL> <IfModule mod_ssl.c> Listen 443 </IfModule> </IfDefine> </IfDefine>
Setup SSL
Enable SSL module
Open “HTTP Server” again in yast2 and enable these “Server Modules”:
- ssl
Copy Keys
Copy the key files from the keystore and place them like this:
- /etc/apache2/ssl.crt/secure.getshifting.com.crt
- /etc/apache2/ssl.key/secure.getshifting.com.key
- /etc/apache2/ssl.crt/intermediate.crt
Setup Local Files
Copy the Outage, Error and Maintenance pages to “/srv/www/htdocs/local”, each in a separate directory:
sjoerd@reverseproxy:/srv/www/htdocs/local> ll drwxr-xr-x 6 root root 4096 2011-01-19 11:29 maintenance drwxr-xr-x 4 root root 4096 2011-01-19 11:30 outage drwxr-xr-x 4 root root 4096 2011-01-19 11:31 error
Also, copy the favicon.ico to “/srv/www/htdocs/”.
NOTE: When using custom error pages, and when these error pages use for example images make sure you use direct links to these images, from the documentroot. If you don't, Apache will look for the images in the directory where the user is, which could be non-existent, wrong and almost never the directory where the images really are.
Setup the Virtual Hosts
Production
/etc/apache2/vhosts.d # cat getshifting-production.conf <IfDefine SSL> <IfDefine !NOSSL> <VirtualHost _default_:443> # Enable proxying ProxyRequests off ProxyPreserveHost on ProxyVia off SSLProxyEngine on # Enable rewriting RewriteEngine on #RewriteLogLevel 2 RewriteLog /var/log/apache2/rewrite.log RewriteRule ^/start$ /start/ [R] RewriteRule ^/startdocuments$ /startdocuments/ [R] # General setup for the virtual host DocumentRoot "/srv/www/htdocs" # Error Logging ErrorLog /var/log/apache2/error_log CustomLog /var/log/apache2/access_log combined # LogLevel info # SSL Settings SSLEngine on SSLProtocol -ALL +SSLv3 +TLSv1 SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP SSLCertificateFile /etc/apache2/ssl.crt/secure.getshifting.com.crt SSLCertificateKeyFile /etc/apache2/ssl.key/secure.getshifting.com.key SSLCACertificateFile /etc/apache2/ssl.crt/intermediate.crt <Files ~ "\.(cgi|shtml|phtml|php3?)$"> SSLOptions +StdEnvVars </Files> <Directory "/srv/www/cgi-bin"> SSLOptions +StdEnvVars </Directory> SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 # Error Documents # Customized error pages are in documentroot/error/ and included in error.conf ProxyErrorOverride On # Proxying rules # Do not proxy ! ProxyPass /local/outage ! ProxyPass /local/maintenance ! ProxyPass /local/error ! ProxyPass /favicon.ico ! # Follow these proxy rules in this order ProxyPass /startdocuments https://10.10.12.20/startdocuments ProxyPassReverse /startdocuments https://10.10.12.20/startdocument ProxyPass /start https://10.10.12.20/start ProxyPassReverse /start https://10.10.12.20/start ProxyPass / https://10.10.12.20/start/ ProxyPassReverse / https://10.10.12.20/start/ </VirtualHost> </IfDefine> </IfDefine>
Outage
/etc/apache2/vhosts.d # cat getshifting-outage.conf_disabled <IfDefine SSL> <IfDefine !NOSSL> <VirtualHost _default_:443> # Enable proxying ProxyRequests off ProxyPreserveHost on ProxyVia off SSLProxyEngine On # Enable rewriting RewriteEngine on #RewriteLogLevel 2 RewriteLog /var/log/apache2/rewrite.log RewriteRule ^/$ /start/ [R] RewriteRule ^/startdocuments/* /start/ [R] # General setup for the virtual host DocumentRoot "/srv/www/htdocs/local/outage" # Error Logging ErrorLog /var/log/apache2/error_log CustomLog /var/log/apache2/access_log combined # LogLevel info # SSL Settings SSLEngine on SSLProtocol -ALL +SSLv3 +TLSv1 SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP SSLCertificateFile /etc/apache2/ssl.crt/secure.getshifting.com.crt SSLCertificateKeyFile /etc/apache2/ssl.key/secure.getshifting.com.key SSLCACertificateFile /etc/apache2/ssl.crt/intermediate.crt <Files ~ "\.(cgi|shtml|phtml|php3?)$"> SSLOptions +StdEnvVars </Files> <Directory "/srv/www/cgi-bin"> SSLOptions +StdEnvVars </Directory> SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 # Error Documents # Customized error pages are in documentroot/error/ and included in error.conf Alias /error/ "/srv/www/htdocs/local/error/" <Directory "/srv/www/htdocs/local/error"> AllowOverride None Order allow,deny Allow from all </Directory> ProxyErrorOverride On # Proxying rules # Do not proxy ! ProxyPass /local/outage ! ProxyPass /local/maintenance ! ProxyPass /local/error ! ProxyPass /favicon.ico ! <Directory "/srv/www/htdocs/local/outage"> AllowOverride None Order allow,deny Allow from all </Directory> </VirtualHost> </IfDefine> </IfDefine>
Maintenance
<IfDefine SSL> <IfDefine !NOSSL> <VirtualHost _default_:443> # Enable proxying ProxyRequests off ProxyPreserveHost on ProxyVia off SSLProxyEngine On # Enable rewriting RewriteEngine on #RewriteLogLevel 2 RewriteLog /var/log/apache2/rewrite.log RewriteRule ^/$ /start/ [R] RewriteRule ^/startdocuments/* /start/ [R] # General setup for the virtual host DocumentRoot "/srv/www/htdocs/local/maintenance" # Error Logging ErrorLog /var/log/apache2/error_log CustomLog /var/log/apache2/access_log combined # LogLevel info # SSL Settings SSLEngine on SSLProtocol -ALL +SSLv3 +TLSv1 SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP SSLCertificateFile /etc/apache2/ssl.crt/secure.getshifting.com.crt SSLCertificateKeyFile /etc/apache2/ssl.key/secure.getshifting.com.key SSLCACertificateFile /etc/apache2/ssl.crt/intermediate.crt <Files ~ "\.(cgi|shtml|phtml|php3?)$"> SSLOptions +StdEnvVars </Files> <Directory "/srv/www/cgi-bin"> SSLOptions +StdEnvVars </Directory> SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 # Error Documents # Customized error pages are in documentroot/error/ and included in error.conf Alias /error/ "/srv/www/htdocs/local/error/" <Directory "/srv/www/htdocs/local/error"> AllowOverride None Order allow,deny Allow from all </Directory> ProxyErrorOverride On # Proxying rules # Do not proxy ! ProxyPass /local/outage ! ProxyPass /local/maintenance ! ProxyPass /local/error ! ProxyPass /favicon.ico ! <Directory "/srv/www/htdocs/local/maintenance"> AllowOverride None Order allow,deny Allow from all </Directory> </VirtualHost> </IfDefine> </IfDefine>
Note that it is possible to rewrite an url to something external as well:^/start$ https://www.maintenancepage.com/systemdown/ [R]
Non-secure vhost
This is an example of a non-secure vhost:
<VirtualHost _default_:80> # Enable proxying ProxyRequests off ProxyPreserveHost on ProxyVia off # Enable rewriting RewriteEngine on #RewriteLogLevel 2 RewriteLog /var/log/apache2/rewrite.log RewriteRule ^/start$ /start/ [R] RewriteRule ^/startdocuments$ /startdocuments/ [R] # General setup for the virtual host DocumentRoot "/srv/www/htdocs" # Error Logging ErrorLog /var/log/apache2/error_log CustomLog /var/log/apache2/access_log combined # LogLevel info # Error Documents # Customized error pages are in documentroot/error/ and included in error.conf ProxyErrorOverride On # Proxying rules # Do not proxy ! ProxyPass /local/outage ! ProxyPass /local/maintenance ! ProxyPass /local/error ! ProxyPass /favicon.ico ! # Follow these proxy rules in this order ProxyPass /startdocuments http://10.10.12.20/startdocuments ProxyPassReverse /startdocuments http://10.10.12.20/startdocument ProxyPass /start http://10.10.12.20/start ProxyPassReverse /start http://10.10.12.20/start ProxyPass / http://10.10.12.20/start/ ProxyPassReverse / http://10.10.12.20/start/ </VirtualHost>
Internet Explorer Friendly HTTP Error Messages
Please note that the ErrorDocument 500 with the message displayal will not work in Internet Explorer with the option “Show friendly HTTP error messages” enabled.
Automatic Monitoring Script
Goal: When the monitoring server sees specific error messages a script should run activating the 'outage' page and warn me.
Monitoring:
- ManageEngine Application Manager 9:
Create new Monitor:
- In AppManager click 'New Monitor' and select 'HTTP(s) URLs
- Fill in data:
- Display Name: Secure Website
- Url address: https://10.10.12.20/start/
- Check for specific html content: Secure GetShifting
- Error if Match: Internal Server Error
- (keep rest default)
- save
Go to the monitor and wait for data collection to start. Check that health is ok.
Configure Action:
- In AppManager click 'Actions' and select 'Execute Program'
- Fill in data:
- Display Name: Start Outage Page in ACC
- Script Location: Remote Server (10.10.10.20 (monuser))
- Program To execute: /opt/Tools/Scripts/outagepage.sh start
- Directory to execute Program: opt/Tools/Scripts
- (keep rest default)
Create the action and test it (start with a script that just creates a file in temp)
Als create one for switching back:
- Program To execute: /opt/Tools/Scripts/outagepage.sh stop
- outagepage.sh
#!/bin/bash ######################################################################################################################## # Author : Sjoerd Hooft # Date Initial Version: 18 Jan 2011 # Comments: sjoerd_getshifting_com # # Description: # This is a the script to automatically switch between two Apache vhost. Default is production, fallback is Outage. # # Recommendations: # The script is designed for a 120 column terminal. # The running user must meet these requirements: # - monitoring user # - sudo commands for renaming config files and reloading apache # - have write permissions in the base directory # # Changes: # Please comment on your changes to the script (your name and email address, line number, description): ######################################################################################################################## # Script Variables HOSTNAME_SHORT=`hostname -s` BASEDIR=`dirname $0` DATE=`date +%Y%m%d%H%M` LOGFILE="$BASEDIR/outagepage$DATE.log" TOMAIL=sjoerd_getshifting_com # Apache directory VHOSTS="/etc/apache2/vhosts.d" # Redirecting all output to logfile exec > $LOGFILE 2>&1 case "$1" in start ) echo "Switching from Production Page to Outages Page" sudo mv $VHOSTS/getshifting-production.conf $VHOSTS/getshifting-production.conf_disabled sudo mv $VHOSTS/getshifting-outage.conf_disabled $VHOSTS/getshifting-outage.conf sudo /etc/init.d/apache2 reload echo "Switching from Production Page to Outages Page... done" cat $LOGFILE | mail -s "ALERT - ${HOSTNAME_SHORT} switched to OUTAGEPAGE" $TOMAIL ;; stop ) echo "Switching from Outages Page to Production Page" sudo mv $VHOSTS/getshifting-production.conf_disabled $VHOSTS/getshifting-production.conf sudo mv $VHOSTS/getshifting-outage.conf $VHOSTS/getshifting-outage.conf_disabled sudo /etc/init.d/apache2 reload echo "Switching from Outage Page to Production Page... done" cat $LOGFILE | mail -s "ALERT CLEARED - ${HOSTNAME_SHORT} switched back to PRODUCTION" $TOMAIL ;; * ) echo echo "Usage: $0 COMMAND" echo "---------------------------" echo "start - Switch from Production Page to Outage Page" echo "stop - Switch from Outage Page to Production Page" echo exit 1 ;; esac exit
Tests
Start Application Server Down
Outages page gets activated! Success!
When the Application Server is back up, the production page gets activated again.
WebServer Down
Outages page gets activated! Success!
When the webserver is up again, the production page gets activated again.
Security Settings
Since this is the reverse proxy, meaning first real point of access from outside, we want added security. This means a setup of three nics:
- Extern IP: 10.10.10.20
- Purpose: external access to the application
- Added to the demilitirized zone in the firewall
- Intern IP: 10.10.12.120
- Purpose: internal access to the appplication and direct access to the application for customers
- Added to the internal zone in the firewall
- Mgmt IP: 10.10.253.120
- Purpose: Monitoring SSH access
- Added to the external zone in the firewall
- Shutdown VM
- Add NICs in correct VLANs
- Startup VM
- Yast2 → Network Devices → Network Settings
- Configure NICs
Test if you can access the proxy over the new nic
- yast2 → Security and Users → firewall
- Interfaces , set the new interface (eth1) in the Internal Zone
- Allowed Services:
- Internal Zone: HTTPS
- External Zone: SSH
- Demilitirized Zone: HTTPS
- Logging Level:
- Logging Accepted Packets: Log Only Critical
- Logging Not Accepted PacketsL Log All
Setup Caching
Please note that caching will only work for non-secure data. It is not possible to cache data from a HTTPS url.
To configure caching, we'll first have to enable it in apache:
- Start yast
- Go to network services
- Select the “HTTP Server”
- Go to “Server Modules”:
- Enable these modules
- cache
- diskcache
Save the changes.
Note: If you forget to enable the cache module you'll get this warning:
sjoerd@reverseproxy:/etc/apache2/vhosts.d> sudo /etc/init.d/apache2 restart httpd2-prefork: Syntax error on line 116 of /etc/apache2/httpd.conf: Syntax error on line 26 of /etc/apache2/sysconfig.d/loadmodule.conf: Cannot load /usr/lib64/apache2-prefork/mod_disk_cache.so into server: /usr/lib64/apache2-prefork/mod_disk_cache.so: undefined symbol: ap_cache_cacheable_hdrs_out
Second disk
Add a second disk to the VM and configure it to mount on /var/cache/apache, the default location for apache cache.
- Disk size: 8 GB
- file system ext3, no access time
- Mountpoint: /var/cache/apache
reverseproxy:~ # mount ... /dev/sdb1 on /var/cache/apache type ext3 (rw,noatime,acl,user_xattr)
And set the owner:
sudo chown -R wwwrun:root /var/cache/apache
Apache Cache
Set the configuration below inside the vhost config file.
# Caching CacheRoot /var/cache/apache CacheEnable disk / CacheDirLevels 1 CacheDirLength 1 CacheDefaultExpire 7200 CacheMaxExpire 86400 CacheIgnoreNoLastMod On CacheMaxFileSize 2048000 CacheStorePrivate On
Apache Cache Resources
http://httpd.apache.org/docs/2.2/caching.html
http://httpd.apache.org/docs/2.2/mod/mod_disk_cache.html
http://www.mnot.net/cache_docs/
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Switch From https To http
This is not really possible, if you need “ProxyPreserveHost on” in Apache. Our application needs that to work through a reverse proxy, setting it to off breaks it. We wanted to configure the reverse proxy from https on the outside, to http on the inside but that seems impossible. It is either http to http, or https to https. I tested both, and they work, but unfortunely switching from https on the outside to http on the inside does not. I experimented with rewriterules, requestheader, and a couple of settings more, no luck.
Mod Security
We want to offload the application webserver as much as possible which means we'll also implement mod_security on the reverse proxy. This will offload and simplify the application webserver.
Mod Security 2.x has these requirements:
- Apache 2.2.x (highly recommended)
- Apache module mod_unique_id
- libapr & libapr-util
- libpcre
- libxml2
All modules are already installed by default. Note that libpcre is known as 'pcre' on SLES.
You just have to enable the module mod_unique_id as it is not enabled by default. Restart to make your changes effective and run httpd2 -M to see if all modules are loaded. If everything is loaded stop apache.
Mod Security Installation
Make sure you have access to the SLES SDK Sources. Since we have an SLES Installation Update Server 11 I could download the SDK ISO DVD1 (which holds all required files) and add it to my software repository.
The ISO can be downloaded from here: SLES 11 SP1 SDK Download (A Novell account is required). The file you need to download is called: SLE-11-SP1-SDK-DVD-x86_64-GM-DVD1.iso
After installing, it's mostly just a module but not entirely. You need to to enable two modules now, the mod_unique_id which is a normal module and can be enabled the normal way:
- yast2 → network services → http server → server modules
- select the module and enable it
The second module to enable is mod_security. Since it is not recognized by apache as a module we have to manually add the module to the modulelist.
Find the APACHE_MODULES in the apache2 sysconfig file and add the module like below:
reverseproxy:/var/log/apache2 # vi /etc/sysconfig/apache2 APACHE_MODULES="authz_host actions alias auth_basic authz_groupfile authn_file authz_user autoindex cgi dir include log_config mime negotiation setenvif status userdir asis cache disk_cache imagemap proxy proxy_connect proxy_http rewrite ssl unique_id authz_default mod_security2"
Restart apache and check wether the modules are running by issuing the 'httpd2 -M' command:
reverseproxy:/var/log/apache2 # httpd2 -M Loaded Modules: core_module (static) mpm_prefork_module (static) http_module (static) so_module (static) authz_host_module (shared) actions_module (shared) alias_module (shared) auth_basic_module (shared) authz_groupfile_module (shared) authn_file_module (shared) authz_user_module (shared) autoindex_module (shared) cgi_module (shared) dir_module (shared) include_module (shared) log_config_module (shared) mime_module (shared) negotiation_module (shared) setenvif_module (shared) status_module (shared) userdir_module (shared) asis_module (shared) cache_module (shared) disk_cache_module (shared) imagemap_module (shared) proxy_module (shared) proxy_connect_module (shared) proxy_http_module (shared) rewrite_module (shared) ssl_module (shared) unique_id_module (shared) authz_default_module (shared) security2_module (shared) Syntax OK
Mod Security Configuration
Mod security has a default configuration file, and comes with a core rule set. The configuration works with include files which work for the modsecurity part like this:
httpd.conf | |-- default-server.conf . . . . . . . . . set up the default server that replies to non-virtual-host requests | `--conf.d/mod_security2.conf . . . . enable mod-security default configuration | `--conf.d/modsecurity/*.conf . . . . . . add the core rule set
Since this include structure is not enabled by default (because the core rule set is not enabled by default) we have to include the core rule set manually.
- Create the correct directories and copy the core rule set config files to this directory:
reverseproxy:/usr/share/doc/packages/apache2-mod_security2/rules # mkdir /etc/apache2/conf.d/modsecurity reverseproxy:/usr/share/doc/packages/apache2-mod_security2/rules # cp *.conf /etc/apache2/conf.d/modsecurity reverseproxy:/usr/share/doc/packages/apache2-mod_security2/rules # cd /etc/apache2/conf.d/modsecurity reverseproxy:/etc/apache2/conf.d/modsecurity # ll -rw-r--r-- 1 root root 12325 Jan 31 14:03 modsecurity_crs_10_config.conf -rw-r--r-- 1 root root 5164 Jan 31 14:03 modsecurity_crs_20_protocol_violations.conf -rw-r--r-- 1 root root 3538 Jan 31 14:03 modsecurity_crs_21_protocol_anomalies.conf -rw-r--r-- 1 root root 2496 Jan 31 14:03 modsecurity_crs_23_request_limits.conf -rw-r--r-- 1 root root 6399 Jan 31 14:03 modsecurity_crs_30_http_policy.conf -rw-r--r-- 1 root root 2720 Jan 31 14:03 modsecurity_crs_35_bad_robots.conf -rw-r--r-- 1 root root 28726 Jan 31 14:03 modsecurity_crs_40_generic_attacks.conf -rw-r--r-- 1 root root 2463 Jan 31 14:03 modsecurity_crs_45_trojans.conf -rw-r--r-- 1 root root 8268 Jan 31 14:03 modsecurity_crs_50_outbound.conf
- Add the include line for the core rule set in the httpd.conf:
# Include Mod Security Core Rule Set Include /etc/apache2/conf.d/modsecurity/*.conf
Now we will configure the config files themselves to run modsecurity first in DetectionOnly mode to prevent the risk for false positives. We also set the logfiles correctly:
vi /etc/apache2/conf.d/mod_security2.conf: # Basic configuration options #SecRuleEngine On SecRuleEngine DetectionOnly
vi /etc/apache2/conf.d/modsecurity/modsecurity_crs_10_config.conf: SecRuleEngine DetectionOnly SecAuditLog /var/log/apache2/modsec_audit.log SecDebugLog /var/log/apache2/modsec_debug.log SecDebugLogLevel 3
Now restart apache:
reverseproxy:/var/log/apache2 # /etc/init.d/apache2 start Starting httpd2 (prefork) [Mon Jan 31 14:30:35 2011] [warn] worker http://10.10.12.20/start already used by another worker [Mon Jan 31 14:30:35 2011] [warn] worker http://10.10.12.20/start already used by another worker
Documentation Core Rule Set
Core Rule Set Structure & Usage ==================================== To activate the rules for your web server installation: 1) You may want to edit and customize modsecurity_crs_10_config.conf. Additionally you may want to edit modsecurity_crs_30_http_policy.conf which enforces an application specific HTTP protocol usage. 2) Add the following line to your httpd.conf (assuming you've placed the rule files into conf/modsecurity/): Include conf/modsecurity/*.conf 3) Restart web server. 4) Make sure your web sites are still running fine. Core Rule Set Content ========================= In order to provide generic web applications protection, the Core Rule Set uses the following techniques: 1. HTTP protection - detecting violations of the HTTP protocol and a locally defined usage policy. 2. Common Web Attacks Protection - detecting common web application security attack. 3. Automation detection - Detecting bots, crawlers, scanners and other surface malicious activity. 4. Trojan Protection - Detecting access to Trojans horses. 5. Errors Hiding - Disguising error messages sent by the server In addition the rule set also hints at the power of ModSecurity beyond providing security by reporting access from the major search engines to your site. HTTP Protection - This first line of protection ensures that all abnormal HTTP requests are detected. This line of defense eliminates a large number of automated and non targeted attacks as well as protects the web server itself. Common Web Attacks Protection Rules on the second level address the common web application security attack methods. These are the issues that can appear in any web application. Some of the issues addressed are: - SQL Injection - Cross-Site Scripting (XSS) - OS Command execution - Remote code inclusion - LDAP Injection - SSI Injection - Information leak - Buffer overflows - File disclosure Automation Detection - Automated clients are both a security risk and a commercial risk. Automated crawlers collect information from your site, consume bandwidth and might also search for vulnerabilities on the web site. Automation detection is especially useful for generic detection of comments spam. Trojan Protection - ModSecurity Core Rule Set detects access to back doors installed on a web server. This feature is very important in a hosting environment when some of this backdoors may be uploaded in a legitimate way and used maliciously. In addition the Core Rule Set includes a hook for adding an Anti-Virus program such as ClamAV for checking file uploads. Errors Hiding - If all fails, the Core Rule Set will detect errors sent by the web server. Detecting and blocking errors prevents attackers from collecting reconnaissance information about the web application and also server as a last line of defense in case an attack was not detected eariler. Few Word of Caution ------------------- As with every new technology, using the ModSecurity Core Rule Set requires some caution: - Every Rule Set can have false positive in new environments and any new installation should initially use the log only Rule Set version or if no such version is available, set ModSecurity to Detection only using the SecRuleEngine DetectionOnly command. After running ModSecurity in a detection only mode for a while review the evens generated and decide if any modification to the rule set should be made before moving to protection mode.
From the mod security manual:
SecRuleEngine Description: Configures the rules engine. Syntax: SecRuleEngine On|Off|DetectionOnly Example Usage: SecRuleEngine On Processing Phase: Any Scope: Any Version: 2.0.0 Dependencies/Notes: This directive can also be controlled by the ctl action (ctl:ruleEngine=off) for per rule processing. Possible values are: * On - process rules. * Off - do not process rules. * DetectionOnly - process rules but never intercept transactions, even when rules are configured to do so.
Mod Security Handling False Positives
Mod security is now configured as detection only. For now, we keep it like this, closely monitoring the mod security logfiles for false positives. When we are sure there are no more false positives (or at least nothing our customers will notice) we can set the SecRuleEngine to On.
This blog also explains how to deal with false positives: Handling False Positives
Mod Security Troubleshooting
Starting httpd2 (prefork) [Mon Jan 31 14:20:51 2011] [warn] worker http://10.10.12.20/start already used by another worker [Mon Jan 31 14:20:51 2011] [warn] worker http://10.10.12.20/start already used by another worker Syntax error on line 53 of /etc/apache2/conf.d/modsecurity/modsecurity_crs_10_config.conf: Invalid command 'SecRuleEngine', perhaps misspelled or defined by a module not included in the server configuration The command line was: /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DSSL
'Solution:
' The module mod_security is not enabled. Check for the module with the command 'httpd2 -M'. If the module is really not there, add the module in /etc/sysconfig/apache2.
reverseproxy:/var/log/apache2 # /etc/init.d/apache2 restart [Mon Jan 31 14:29:23 2011] [warn] worker http://10.10.12.20/start already used by another worker [Mon Jan 31 14:29:23 2011] [warn] worker http://10.10.12.20/start already used by another worker Syntax error on line 191 of /etc/apache2/conf.d/modsecurity/modsecurity_crs_10_config.conf: ModSecurity: Failed to open the audit log file: /srv/www/logs/modsec_audit.log
'Solution:
' The directory specified for the logs does not exist. Create the directory with this command:
- reverseproxy:/var/log/apache2 # mkdir -p /srv/www/logs/
or change the location to /var/log/apache2. Of course, the same message can be displayed for /srv/www/logs/modsec_debug.log.
Testing Mod Security
You can test if mod security is running correctly by going to the index file of your website by ip-address and adding '?file=/etc/passwd' to the url:
https://10.10.10.20/start/index.html?file=/etc/passwd
This will be noticed, and displayed in the log (not stopped, remember, we're running in DetectionOnly mode):
- less modsec_debug.log
[31/Jan/2011:15:46:31 +0100] [10.10.10.20/sid#7f0c98cffdc8][rid#7f0c98feb488][/start/0100_NavigationPublic.html][2] Warning. Pattern match "^[\d\.]+$" at REQUEST_HEADERS:Host. [ file "/etc/apache2/conf.d/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "60"] [id "960017"] [msg "Host header is a numeric IP address"] [severity "CRITICAL"] [ta g "PROTOCOL_VIOLATION/IP_HOST"] [31/Jan/2011:15:46:42 +0100] [10.10.10.20/sid#7f0c98cffdc8][rid#7f0c98fe2908][/start/index.html][2] Warning. Pattern match "^[\d\.]+$" at REQUEST_HEADERS:Host. [file "/etc/apach e2/conf.d/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "60"] [id "960017"] [msg "Host header is a numeric IP address"] [severity "CRITICAL"] [tag "PROTOCOL_VIOL ATION/IP_HOST"] [31/Jan/2011:15:46:42 +0100] [10.10.10.20/sid#7f0c98cffdc8][rid#7f0c98fe2908][/start/index.html][2] Warning. Pattern match "(?:\b(?:\.(?:ht(?:access|passwd|group)|www_?acl)|glob al\.asa|httpd\.conf|boot\.ini)\b|\/etc\/)" at ARGS:file. [file "/etc/apache2/conf.d/modsecurity/modsecurity_crs_40_generic_attacks.conf"] [line "114"] [id "950005"] [msg "Remote File Access Attempt"] [data "/etc/"] [severity "CRITICAL"] [tag "WEB_ATTACK/FILE_INJECTION"] [31/Jan/2011:15:46:42 +0100] [10.10.10.20/sid#7f0c98cffdc8][rid#7f0c98fe2908][/start/index.html][2] Warning. Pattern match "(?:\b(?:(?:n(?:et(?:\b\W+?\blocalgroup|\.exe)|(?:map| c)\.exe)|t(?:racer(?:oute|t)|elnet\.exe|clsh8?|ftp)|(?:w(?:guest|sh)|rcmd|ftp)\.exe|echo\b\W*?\by+)\b|c(?:md(?:(?:32)?\.exe\b|\b\W*?\/c)|d(?:\b\W*?[\\/]|\W*?\.\.)|hmod.{0,40}?\+. {0,3}x))|[\;\|\`]\W*? ..." at ARGS:file. [file "/etc/apache2/conf.d/modsecurity/modsecurity_crs_40_generic_attacks.conf"] [line "133"] [id "950006"] [msg "System Command Injectio n"] [data "/passwd"] [severity "CRITICAL"] [tag "WEB_ATTACK/COMMAND_INJECTION"]
- less modsec_audit.log:
Message: Warning. Pattern match "^[\d\.]+$" at REQUEST_HEADERS:Host. [file "/etc/apache2/conf.d/modsecurity/modsecurity_crs_21_protocol_anomalies.conf"] [line "60"] [id "960017"] [msg "Host header is a numeric IP address"] [severity "CRITICAL"] [tag "PROTOCOL_VIOLATION/IP_HOST"] Apache-Handler: proxy-server Stopwatch: 1296487473036980 19376 (997 2882 -) Producer: ModSecurity for Apache/2.5.6 (http://www.modsecurity.org/); core ruleset/1.6.1. Server: Apache/2.2.10 (Linux/SUSE)
Mod Security Resources
http://www.modsecurity.org/
http://www.modsecurity.org/documentation/faq.html
http://www.modsecurity.org/documentation/modsecurity-apache/2.5.12/html-multipage/introduction.html
Install Modsecurity
Install core rule set
Futher Apache Hardening
Prevent Information Leaks
To prevent information leaks set the following options as described:
- Add ServerSignature Off
- The ServerSignature directive allows the configuration of a trailing footer line under server-generated documents
- Add ServerTokens ProductOnly
- This directive controls whether Server response header field which is sent back to clients includes a description of the generic OS-type of the server as well as information about compiled-in modules
These options are set in this file: /etc/sysconfig/apache2:
APACHE_SERVERSIGNATURE="off" APACHE_SERVERTOKENS="ProductOnly"
After restarting Apache you can check these settings in
reverseproxy:/etc/apache2 # cat /etc/apache2/sysconfig.d/global.conf # # Files in this directory are created at apache start time by /usr/sbin/rcapache2 # Do not edit them! # # see /etc/sysconfig/apache2 ServerSignature off UseCanonicalName off ServerTokens ProductOnly LogLevel warn CustomLog /var/log/apache2/access_log combined
Directory And Files Security
Apache can also be extra secured by setting restrictions on which files and directories may be served by the webserver. This is controlled by the 'Directory' directive, which can be used in several configuration files. By default, apache on SLES opens up several directories which are not necessary for our environment. This is the default directory include hierarchy:
httpd.conf . . . . . . . . . . . . . . . . denies access for the entire filesystem | |-- errors.conf . . . . . . . . . . . . . includes the directory where Apache customized errors are located | `-- default-server.conf . . . . . . . . . sets the document root, icons and cgi directory `--mod_userdir.conf . . . . . . . . opens user home directories
httpd.conf
# forbid access to the entire filesystem by default <Directory /> Options None AllowOverride None Order deny,allow Deny from all </Directory>
The httpd.conf is all right like this. Access to the entire filesystem is denied by default and must be explicitly overridden by for example vhosts.
errors.conf
Alias /error/ "/usr/share/apache2/error/" <Directory "/usr/share/apache2/error"> AllowOverride None Options IncludesNoExec AddOutputFilter Includes html AddHandler type-map var Order allow,deny Allow from all LanguagePriority en cs de es fr it ja ko nl pl pt-br ro sv tr ForceLanguagePriority Prefer Fallback </Directory>
Since we'll be using our own errors pages there is no use anymore for keeping this directory. It should be commented out, and new error pages should be defined.
New errors.conf
Alias /local/error/ "/srv/www/htdocs/local/error/" <IfModule mod_negotiation.c> <IfModule mod_include.c> ErrorDocument 400 /local/error/index.html ErrorDocument 401 /local/error/index.html ErrorDocument 403 /local/error/index.html ErrorDocument 404 /local/error/index.html ErrorDocument 405 /local/error/index.html ErrorDocument 408 /local/error/index.html ErrorDocument 410 /local/error/index.html ErrorDocument 411 /local/error/index.html ErrorDocument 412 /local/error/index.html ErrorDocument 413 /local/error/index.html ErrorDocument 414 /local/error/index.html ErrorDocument 415 /local/error/index.html ErrorDocument 500 /local/error/index.html ErrorDocument 501 /local/error/index.html ErrorDocument 502 /local/error/index.html ErrorDocument 503 /local/error/index.html ErrorDocument 506 /local/error/index.html </IfModule> </IfModule>
default-server.conf
<Directory "/srv/www/htdocs"> Options None AllowOverride None Order allow,deny Allow from all </Directory>
This allows files to be served from the document root but nothing more. This is sufficient for our setup, since it allows the local error, outage and maintenance pages to be loaded.
Alias /icons/ "/usr/share/apache2/icons/" <Directory "/usr/share/apache2/icons"> Options Indexes MultiViews AllowOverride None Order allow,deny Allow from all </Directory>
We will not use the Apache icons, they can be commented out.
ScriptAlias /cgi-bin/ "/srv/www/cgi-bin/" <Directory "/srv/www/cgi-bin"> AllowOverride None Options +ExecCGI -Includes Order allow,deny Allow from all </Directory>
This allows cgi-scripts to be executed, but it doesn't allow includes. As far as cgi-scripts are concerned, this is a pretty safe setup, and can be left like this.
mod_userdir.conf:
<Directory /home/*/public_html> AllowOverride FileInfo AuthConfig Limit Indexes Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec <Limit GET POST OPTIONS PROPFIND> Order allow,deny Allow from all </Limit> <LimitExcept GET POST OPTIONS PROPFIND> Order deny,allow Deny from all </LimitExcept> </Directory>
According to the Apache documentation about mod_userdir the module is only used for serving pages from the home directory of users. This is a potential security risk and we will not only disable the module, we will also comment this out from the config file in case someone ever enabled the directory again.
Limiting Concurrency
Another way of making Apache more secure is by setting limits on the amount of processes Apache is allowed to process.
These settings consist of:
- Maximums for the module prefork
- Maximums for the module worker
- Timeout
- KeepAlive settings
On SLES these settings are already implemented in the server-tuning.conf:
/etc/apache2> cat server-tuning.conf | grep -v '^$' | grep -v '^#' <IfModule prefork.c> # number of server processes to start # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#startservers StartServers 5 # minimum number of server processes which are kept spare # http://httpd.apache.org/docs/2.2/mod/prefork.html#minspareservers MinSpareServers 5 # maximum number of server processes which are kept spare # http://httpd.apache.org/docs/2.2/mod/prefork.html#maxspareservers MaxSpareServers 10 # highest possible MaxClients setting for the lifetime of the Apache process. # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit ServerLimit 150 # maximum number of server processes allowed to start # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxclients MaxClients 150 # maximum number of requests a server process serves # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxrequestsperchild MaxRequestsPerChild 10000 </IfModule> <IfModule worker.c> # initial number of server processes to start # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#startservers StartServers 3 # minimum number of worker threads which are kept spare # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#minsparethreads MinSpareThreads 25 # maximum number of worker threads which are kept spare # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxsparethreads MaxSpareThreads 75 # upper limit on the configurable number of threads per child process # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#threadlimit ThreadLimit 64 # maximum number of simultaneous client connections # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxclients MaxClients 150 # number of worker threads created by each child process # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#threadsperchild ThreadsPerChild 25 # maximum number of requests a server process serves # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxrequestsperchild MaxRequestsPerChild 10000 </IfModule> Timeout 30 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 15
AWStats
I also added awstats to the server, a statistics tool. I explained how on this page.