If we use apache for services with user authentication we want to it to talk to Active Directory. It is possible to have Linux talk to the AD servers for user authentication. Apache can be configured to piggy back on top of this setup. There are 2 steps

PAM talking to ActiveDirectory

This is pretty easy and already documented at ActiveDirectory.

Apache authenticating externally

There are many ways to make apache use external authentication systems. the few we are interested in:

  • mod-auth-pam
  • mod-authnz-external
  • mod-auth-ldap
  • Apache::AuthPAM

Apache talking to PAM

It sounds simple but has not been easy to do this. For some security reasons having apache talk to pam (the linux authentication system) is not common.

I want to configure winbind+pam like I do on the other services so that I'm not maintaning and configuring multiple authentications systems.

mod-auth-pam

This module is no longer maintained. For this reason I do not want to use it but it is the closest I have gotten to getting this stuff to work the way I want. Using other modules introduces more dependencies on other systems. http://pam.sourceforge.net/mod_auth_pam/

You must add these two lines into the Directory section of your apache config

AuthPAM_Enabled on
AuthBasicAuthoritative off

For AuthBasicAuthoritative details see http://www.nabble.com/Bug-394097%3A-libapache2-mod-auth-pam-with-apache-%3E%3D-2.1-needs-AuthBasicAuthoritative-Off-tt7549314.html#a7549314

If authenticating against local users in the system you must also give the apache process read access to /etc/shadow. THIS IS A HUGE SECURITY RISK. The good news is that we don't really need that because we are authenticating against ActiveDirectory.

Check /etc/pam.d/httpd or /etc/pam.d/apache2 to make sure that the apache pam process is using the common pam authentication rather than some other modules or settings.

Debian

apt-get install libapache2-mod-auth-pam

Check /etc/pam.d/apache2

@include common-auth
@include common-account

RedHat/CentOS 5

Since the module is not a built in package in RedHat I prefer to CompileFromSource. There are a few repositories on the web which have the module pre-compiled. WARNING It is risky to use software compiled by other people. You need to be able to trust the entity creating your software. This sounds paranoid because it is. Paranoia is the best way to keep systems secure.

Check /etc/pam.d/httpd. create it if it does not exist.

#%PAM-1.0
auth       include      system-auth
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
session    include      system-auth

Apache::AuthPAM

http://search.cpan.org/~hdaniel/Apache-AuthPAM-0.01/AuthPAM.pm

Apache using other authentication systems

mod-authnz-external

This is a module that allows apache to use an external source for authentication. Unfortunately, I havent' found documentation on how to use pam as the external source.

mod-auth-ldap

LDAP can be used to talk to ActiveDirectory but I don't want to configure two systems.

Apache using Active Directory through mod_auth_pam

First I setup pam to authenticate against ActiveDirectory and tested with ssh. Next I modified apache's configs to use pam authentication.

Main site

If you want to password protect the main website on the server you need to modify the main configuration file for apache.

Debian

Modify /etc/apache2/sites-available/default

NameVirtualHost *
<VirtualHost *>
       ServerAdmin webmaster@domain.com
       ServerName hg.domain.com
       DocumentRoot /var/www/

       <Directory />
               AuthType basic
               AuthName "Active Directory Authentication Required"
               AuthPAM_Enabled on
               AuthBasicAuthoritative off  
               Require valid-user

               Options FollowSymLinks
               AllowOverride None
       </Directory>
       ErrorLog /var/log/apache2/error.log
       LogLevel warn

       CustomLog /var/log/apache2/access.log combined
       ServerSignature On
</VirtualHost>

RedHat

Edit /etc/httpd/conf/httpd.conf

<Directory />
        AuthType basic
        AuthName "Active Directory Authentication Required"
        AuthPAM_Enabled on
        AuthBasicAuthoritative off  
        Require valid-user

        Options FollowSymLinks
        AllowOverride None
</Directory>

Virtual Host

If the password protected site is only one of many virtual hosts you will need to configure it outside of the main website config.

RedHat

I suggest creating a file to contain the virtual hosts or append to one if you already have it. Put the following section in /etc/httpd/conf.d/vhosts.conf

NameVirtualHost *:80

<VirtualHost *:80>
   ServerAdmin webmaster@domain.com
   DocumentRoot /var/www/vhosts/domain.com
   ServerName mysite.domain.com

 <Directory />
       AuthType basic
       AuthName "Active Directory Authentication Required"
       AuthPAM_Enabled on
       AuthBasicAuthoritative off
       Require valid-user

       Options FollowSymLinks
       AllowOverride None
 </Directory>

</VirtualHost>

Now create the directory for the virtual site

mkdir -p /var/www/vhosts/hg.domain.com

Put a test index.html file in place and see if it works

printf "<html><body>It works\!</body></html>\n" > /var/www/vhosts/hg.domain.com/index.html

Each new site can be appended to this file.

Debian

Assuming that you do not already have virtual hosts: By default the configuration exports /var/www for the entire web tree. Backup the original default file and change it so that we can put the virtual hosts inside /var/www.

mv /etc/apache2/sites-available/default /etc/sites-available/default.orig

We will move the main site to /var/www/html. Create a new file /etc/apache2/sites-available/default with the following contents

NameVirtualHost *:80
<VirtualHost *:80>
       ServerAdmin webmaster@localhost
       DocumentRoot /var/www/html
       <Directory />
               Options FollowSymLinks
               AllowOverride None
       </Directory>
       <Directory /var/www/html>
               Options Indexes FollowSymLinks MultiViews
               AllowOverride None
               Order allow,deny
               allow from all
       </Directory>

       ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
       <Directory "/usr/lib/cgi-bin">
               AllowOverride None
               Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
               Order allow,deny
               Allow from all
       </Directory>

       ErrorLog /var/log/apache2/error.log

       # Possible values include: debug, info, notice, warn, error, crit, alert, emerg.
       LogLevel warn
       CustomLog /var/log/apache2/access.log combined
       ServerSignature On

   Alias /doc/ "/usr/share/doc/"
   <Directory "/usr/share/doc/">
       Options Indexes MultiViews FollowSymLinks
       AllowOverride None
       Order deny,allow
       Deny from all
       Allow from 127.0.0.0/255.0.0.0 ::1/128
   </Directory>
</VirtualHost>

Next we create another file for the virtual host site. You might call it mysite.

LoadModule auth_pam_module modules/mod_auth_pam.so
NameVirtualHost *:80
<VirtualHost *:80>
      ServerAdmin webmaster@localhost
      ServerName mysite.domain.com

      DocumentRoot /var/www/vhosts/mysite.domain.com
      <Directory />
              Options FollowSymLinks
              AllowOverride None
      </Directory>
      <Directory /var/www/vhosts/mysite.domain.com>
              Options Indexes FollowSymLinks MultiViews
              AllowOverride None
              Order allow,deny
              allow from all
      </Directory>
</VirtualHost>

Create the two new directories

mkdir -p /var/www/html
mkdir -p /var/www/vhosts/mysite.domain.com

Enable the virtual host in apache with a2ensite. If that does not work then manually link the site

ln -s ../sites-available/mysite /etc/apache2/sites-enabled/mysite

Virtual Host with SSL

Since this site is authenticating you may want to use SSL to encrypt the session. Note the use of port 443 in the examples below and the addition of the SSL lines in the apache configs.

RedHat

Generate a certificate for use on the SSL site.

cd /etc/pki/tls/certs
make mysite.domain.com.pem

If you want to only use ssl change the following section in /etc/httpd/conf.d/vhosts.conf. If you want both ssl and non ssl add this to the already existing file.

LoadModule auth_pam_module modules/mod_auth_pam.so
NameVirtualHost *:443

<VirtualHost *:443>
   ServerAdmin webmaster@domain.com
   DocumentRoot /var/www/vhosts/domain.com
   ServerName mysite.domain.com
    SSLEngine On
    SSLCertificateFile /etc/pki/tls/certs/mysite.domain.com.pem

 <Directory />
       AuthType basic
       AuthName "Active Directory Authentication Required"
       AuthPAM_Enabled on
       AuthBasicAuthoritative off
       Require valid-user

       Options FollowSymLinks
       AllowOverride None
 </Directory>

</VirtualHost>

Debian

Install the ssl-cert package and generate a certificate. Fill in the appropriate values when asked.

apt-get install ssl-cert
/usr/sbin/make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/ssl/certs/mysite.domain.com.pem

Enable ssl.

a2enmod ssl

Modify the mysite configuration. If you want only ssl change to the text below. If you want both ssl and non ssl add this text to the file.

NameVirtualHost *:443
<VirtualHost *:443>
      ServerAdmin webmaster@localhost
      ServerName mysite.domain.com
      SSLEngine On
      SSLCertificateFile /etc/ssl/certs/mysite.domain.com.pem

      DocumentRoot /var/www/vhosts/mysite.domain.com
      <Directory />
              Options FollowSymLinks
              AllowOverride None
      </Directory>
      <Directory /var/www/vhosts/mysite.domain.com>
              Options Indexes FollowSymLinks MultiViews
              AllowOverride None
              Order allow,deny
              allow from all
      </Directory>

      ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
      <Directory "/usr/lib/cgi-bin">
              AllowOverride None
              Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
              Order allow,deny
              Allow from all
      </Directory>
</VirtualHost>

If the user will not authenticate after doing all this stuff try restarting the system. It may be that some service is affected that I don't know about. Restarting seems to allow the authentication to work.

SELinux

SELinux is stopping pam from responding properly to apache. If I turn it off it works ok. I'll create a custom SELINUX policy to allow this to work.

tail /var/log/audit/audit.log | audit2allow -m modauthpam > modauthpam.te
checkmodule  -m -M -omodauthpam.mod modauthpam.te
semodule_package -o modauthpam.pp -m modauthpam.mod
semodule -i modauthpam.pp

After running this in loops to create custom rules I ended up with this for modauthpam.te

module modauthpam 1.0;

require {
       type httpd_t;
       class netlink_audit_socket create;
}

require {
        type httpd_t;
        class netlink_audit_socket write;
} 

require {
        type httpd_t;
        class netlink_audit_socket read;
} 

require {
        type httpd_t;
        class netlink_audit_socket { write nlmsg_relay };
} 

require {
        type httpd_t;
        class netlink_audit_socket { nlmsg_relay read };
}

#============= httpd_t ==============
allow httpd_t self:netlink_audit_socket { nlmsg_relay read };
allow httpd_t self:netlink_audit_socket create;
allow httpd_t self:netlink_audit_socket { write nlmsg_relay };
allow httpd_t self:netlink_audit_socket write;
allow httpd_t self:netlink_audit_socket read;