Getting Squid to authenticate with kerberos and Windows 2008/2003/7/XP

This is setup with Squid 3.0, has also been tested with Squid 3.1 and should work with Squid 2.7. Your Windows user must be a member of the SQUID_USERS group in Active Directory (for this case anyway).

On the Windows side, Windows XP and Windows 2007 have been tested against Windows 2008, and Windows XP against Windows 2003.

Note that almost every step requires the one before it to proceed.

If you have a problem, DNS is always the first place to look. Both Windows machines should be able to ping the Linux server by name (and vice versa), and you may need to run ipconfig /flushdns at times. A reboot may help too, if you want to be really sure there's no cruft hanging around.

Domain info

  • Windows domain: dom.local
  • Domain server: server.dom.local, 172.17.3.11
  • CentOS squid server: centos.dom.local, 172.17.3.10

Domain server setup

  1. Create dom.local reverse zone in the DNS config.
  2. Create static ('A') record for centos.dom.local pointing to 172.17.3.10, select Yes when asked if you want to setup the reverse PTR as well.

Windows 2008

For Windows 2008 server you need to install Hotfix 951191.

Linux Setup

Minor packages

Install packages

$ yum install -y cyrus-sasl-gssapi cvs autoconf automake openldap openldap-devel krb5-workstation krb5-devel gcc-c++

Install msktutil. You need to patch it before you build it.

$ wget http://download.systemimager.org/~finley/msktutil/msktutil_0.3.16.orig.tar.gz
$ wget http://download.systemimager.org/~finley/msktutil/msktutil_0.3.16-7.diff.gz
$ gunzip msktutil_0.3.16-7.diff.gz
$ tar zxf msktutil_0.3.16.orig.tar.gz
$ cd msktutil-0.3.16
$ patch < ../msktutil_0.3.16-7.diff
$ ./configure && make && make install

Compile the latest squid_kerb_ldap.

$ cvs -z3 -d:pserver:[email protected]:/cvsroot/squidkerbauth co -P squid_kerb_ldap
$ cd squid_kerb_ldap
$ ./configure && make

DNS

Use system-config-network to configure the DNS point to the domain controller, set the hostname to centos.dom.local.

Reboot

Check reverse DNS is working: $ dig -x 172.17.3.10

You should get centos.dom.local in the answer section. If you don't there is no point continuing. Kerberos authentication will not work without DNS configured properly.

Kerberos

Your krb.conf should look like something like this:

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = DOM.LOCAL
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h

# For Windows XP:
 default_tgs_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
 default_tkt_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
 permitted_enctypes = rc4-hmac des-cbc-crc des-cbc-md5

# For Windows 2007:
# default_tgs_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
# default_tkt_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
# permitted_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
 forwardable = yes

[realms]
 DOM.LOCAL = {
  kdc = 172.17.3.11:88
  admin_server = 172.17.3.11:7491
  default_domain = dom.local
 }

[domain_realm]
 .dom.local = DOM.LOCAL
 dom.local = DOM.LOCAL

[appdefaults]
 pam = {
   debug = false
   ticket_lifetime = 36000
   renew_lifetime = 36000
   forwardable = true
   krb4_convert = false
}

Create keytab:

$ kinit administrator
$ msktutil -c -b "CN=COMPUTERS" -s HTTP/centos.dom.local -h centos.dom.local -k /etc/HTTP.keytab --computer-name centos-http --upn HTTP/centos.dom.local --server server.dom.local --verbose

For Windows 2008 you need to add --enctypes 28 to the msktutil command.

Squid

Install squid:

$ wget http://www.squid-cache.org/Versions/v3/3.0/squid-3.0.STABLE18.tar.gz
$ tar zxvf squid-3.0.STABLE18.tar.gz 
$ cd squid-3.0.STABLE18
$ ./configure --enable-negotiate-auth-helpers=squid_kerb_auth --enable-stacktraces --prefix=/opt/squid-3.0
$ make
$ make install
$ cp helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth /opt/squid-3.0/sbin/
$ cp ~/squid_kerb_ldap/squid_kerb_ldap /opt/squid-3.0/sbin/
$ cd /opt/squid-3.0/
$ mv etc/squid.conf etc/squid.conf.ORIG

Setup the appropriate parameters in squid.conf:

auth_param negotiate program /opt/squid-3.0/sbin/squid_kerb_auth -d -s HTTP/centos.dom.local
auth_param negotiate children 10
auth_param negotiate keep_alive o

external_acl_type SQUID_KERB_LDAP ttl=3600  negative_ttl=3600  %LOGIN /opt/squid-3.0/sbin/squid_kerb_ldap -d -g SQUID_USERS
acl AUTHENTICATED proxy_auth REQUIRED
acl LDAP_GROUP_CHECK external SQUID_KERB_LDAP
acl localnet src 172.17.3.0/24        # RFC1918 possible internal network

#http_access allow localnet
#http_access allow AUTHENTICATED
http_access allow LDAP_GROUP_CHECK

cache_dir ufs /var/cache/squid-3.0 100 16 256
access_log /var/log/squid-3.0/access.log squid
cache_log /var/log/squid-3.0/cache.log
cache_store_log /var/log/squid-3.0/store.log
pid_filename /var/run/squid-3.0.pid
cache_effective_user squid
cache_effective_group squid
coredump_dir /var/cache/squid-3.0

Setup the user and directories:

$ chown -R squid:squid /opt/squid-3.0/
$ mkdir /var/cache/squid-3.0
$ chown -R squid:squid /var/cache/
$ mkdir /var/log/squid-3.0
$ chown -R squid:squid /var/log/squid-3.0/
$ chown squid:squid /etc/HTTP.keytab

Create caches:

$ /opt/squid-3.0/sbin/squid -z

Init script

Now this is important: Squid needs some environment variables setup to run properly. The best way to do this is to use an init script. Here's a slightly edited CentOS one:

#!/bin/bash
# squid     This shell script takes care of starting and stopping
#       Squid Internet Object Cache
#
# chkconfig: - 90 25
# description: Squid - Internet Object Cache. Internet object caching is \
#   a way to store requested Internet objects (i.e., data available \
#   via the HTTP, FTP, and gopher protocols) on a system closer to the \
#   requesting site than to the source. Web browsers can then use the \
#   local Squid cache as a proxy HTTP server, reducing access time as \
#   well as bandwidth consumption.
# pidfile: /var/run/squid-3.0.pid
# config: /opt/squid-3.0/etc/squid.conf

PATH=/usr/bin:/sbin:/bin:/usr/sbin
export PATH

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# don't raise an error if the config file is incomplete
# set defaults instead:
SQUID_OPTS=${SQUID_OPTS:-"-D"}
SQUID_PIDFILE_TIMEOUT=${SQUID_PIDFILE_TIMEOUT:-20}
SQUID_SHUTDOWN_TIMEOUT=${SQUID_SHUTDOWN_TIMEOUT:-100}

KRB5_KTNAME=/etc/HTTP.keytab
export KRB5_KTNAME

# determine the name of the squid binary
[ -f /opt/squid-3.0/sbin/squid ] && SQUID=/opt/squid-3.0/sbin/squid

prog="$SQUID"

# determine which one is the cache_swap directory
CACHE_SWAP=`sed -e 's/#.*//g' /opt/squid-3.0/etc/squid.conf | \
    grep cache_dir |  awk '{ print $3 }'`
[ -z "$CACHE_SWAP" ] && CACHE_SWAP=/var/spool/squid-3.0

RETVAL=0

start() {

        #check if the squid conf file is present
        if [ ! -f /opt/squid-3.0/etc/squid.conf ]; then
            echo "Configuration file /opt/squid-3.0/etc/squid.conf missing" 1>&2
            exit 6
        fi
        . /etc/sysconfig/squid

        # don't raise an error if the config file is incomplete.
        # set defaults instead:
        SQUID_OPTS=${SQUID_OPTS:-"-D"}
        SQUID_PIDFILE_TIMEOUT=${SQUID_PIDFILE_TIMEOUT:-20}
        SQUID_SHUTDOWN_TIMEOUT=${SQUID_SHUTDOWN_TIMEOUT:-100}

        if [ -z "$SQUID" ]; then
                echo "Insufficient privilege" 1>&2
                exit 4
        fi

        for adir in $CACHE_SWAP; do
        if [ ! -d $adir/00 ]; then
         echo -n "init_cache_dir $adir... "
         $SQUID -z -F -D >> /var/log/squid-3.0/squid.out 2>&1
    fi
    done
    echo -n $"Starting $prog: "
    $SQUID $SQUID_OPTS >> /var/log/squid-3.0/squid.out 2>&1
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
       timeout=0;
       while : ; do
          [ ! -f /var/run/squid-3.0.pid ] || break
      if [ $timeout -ge $SQUID_PIDFILE_TIMEOUT ]; then
         RETVAL=1
         break
      fi
      sleep 1 && echo -n "."
      timeout=$((timeout+1))
       done
    fi
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/squid-3.0
    [ $RETVAL -eq 0 ] && echo_success
    [ $RETVAL -ne 0 ] && echo_failure
    echo
    return $RETVAL
}

stop() {
    . /etc/sysconfig/squid

    # don't raise an error if the config file is incomplete.
    # set defaults instead:
    SQUID_SHUTDOWN_TIMEOUT=${SQUID_SHUTDOWN_TIMEOUT:-100}

    echo -n  $"Stopping $prog: "
    $SQUID -k check >> /var/log/squid-3.0/squid.out 2>&1
    RETVAL=$?
    if [ $RETVAL -eq 0 ] ; then
        $SQUID -k shutdown &
        rm -f /var/lock/subsys/squid-3.0
    timeout=0
    while : ; do
        [ -f /var/run/squid-3.0.pid ] || break
        if [ $timeout -ge $SQUID_SHUTDOWN_TIMEOUT ]; then
            echo
            return 1
        fi
        sleep 2 && echo -n "."
        timeout=$((timeout+2))
        done
    echo_success
    echo
    else
        echo_failure
    echo
    fi
    return $RETVAL
}

reload() {
    . /etc/sysconfig/squid
    # don't raise an error if the config file is incomplete.
    # set defaults instead:
    SQUID_OPTS=${SQUID_OPTS:-"-D"}

    $SQUID $SQUID_OPTS -k reconfigure
}

restart() {
    stop
    start
}

condrestart() {
    [ -e /var/lock/subsys/squid-3.0 ] && restart || :
}

rhstatus() {
    status $SQUID && $SQUID -k check
}

probe() {
    return 0
}

case "$1" in
start)
    start
    ;;

stop)
    stop
    ;;

reload)
    reload
    ;;

restart)
    restart
    ;;

condrestart)
    condrestart
    ;;

status)
    rhstatus
    ;;

probe)
    exit 0
    ;;

*)
    echo $"Usage: $0 {start|stop|status|reload|restart|condrestart}"
    exit 2
esac

exit $?

These are the important lines:

KRB5_KTNAME=/etc/HTTP.keytab
export KRB5_KTNAME

Client Machine

Set your proxy to server centos.dom.local using port 3128. It is important that you use the fully qualified domain name and NOT the IP address.


Instead of editing /etc/init.d/squid to set the KRB5_KTNAME environment variable you should just put the lines in /etc/sysconfig/squid. Since the init script sources /etc/sysconfig/squid on every execution it will pick up those 2 lines.

Additionally, you do not need to explicitly name the hosts to be the KDC and the kadmin server, it is enough to merely enter the DNS domain for your Active Directory domain. There are 2 reasons why:

  1. MIT Kerberos and Heimdal kerberos are both smart enough to use the same SRV records Windows clients use to locate the KDC and the kadmin server
  2. The DNS domain (dom.local in your example) will return A records pointing to your domain controllers