Eric Radman : a Journal

Authenticating VPN Users with FreeRADIUS

Fond of Simple

If you're new to RADIUS then the following configuration won't seem simple, but I think it is reduced enough to actually understand. I discovered by accident that man of the queries can be cut out of the SQL config altogether.

In this instance this service is only acting as a backup for one of our customers, so I placed the configuration under their user account and start it under rc.local listening on it's own IP.

radiusd -d /home/customer1/etc/raddb -l /home/customer1/var/log \
    -a /home/customer1/var/log/radacct -y

radiusd.conf

There are two useful schemes that can be used for PAP: clear and crypt. If you set encryption_scheme to clear then plain passwords will work, otherwise you need to encode passwords with DES. One way to do this is to use Apache's htpasswd to build a list and then copy it into your database.

My users table looks like this:

> select * from vpn_users;
 id | username |   password
 ----+----------+---------------
   1 | eric     | sHuZgk2W607ZA
   2 | laura    | shJFKECSp027c
prefix = /usr
home = /home/customer1
exec_prefix = ${prefix}
sysconfdir = ${home}/etc
localstatedir = ${prefix}/var
sbindir = ${exec_prefix}/sbin
logdir = ${home}/var/log
raddbdir = ${sysconfdir}/raddb
radacctdir = ${logdir}

confdir = ${raddbdir}
run_dir = ${localstatedir}/run/radiusd

log_file = ${logdir}/radius.log

libdir = /usr/lib

pidfile = ${home}/var/run/radiusd.pid

user = customer1
group = users

max_request_time = 30
delete_blocked_requests = no
cleanup_delay = 5
max_requests = 512
bind_address = 10.23.0.1
port = 1645
hostname_lookups = no
allow_core_dumps = no
log_stripped_names = yes
log_auth = yes
log_auth_badpass = yes
log_auth_goodpass = yes
usercollide = no

wer_user = no
lower_pass = no
nospace_user = no
nospace_pass = no

security {
        max_attributes = 200
        reject_delay = 1
        status_server = yes
}

proxy_requests  = no

$INCLUDE  ${confdir}/clients.conf

thread pool {
        start_servers = 1
        max_servers = 2
        min_spare_servers = 1
        max_spare_servers = 1
        max_requests_per_server = 1
}

modules {
        preprocess {
             hints = ${confdir}/hints
        }

        pap {
                encryption_scheme = crypt
                md5 {
                }
        }

        $INCLUDE  ${confdir}/postgresql.conf
            hints = ${confdir}/hints
        }

        pap {
                encryption_scheme = crypt
                md5 {
                }
        }

        $INCLUDE  ${confdir}/postgresql.conf

        always fail {
                rcode = fail
        }

        always reject {
                rcode = reject
        }

        always ok {
                rcode = ok
        }
}

authorize {
        preprocess
        sql
}

authenticate {
        Auth-Type PAP {
                pap
        }
}

postgresql.conf

When searching discussion groups it appears that everyone plases the attribute and op fields in the database, but there's no reason to do this in my applications, so I simple select a string and use AS to title the field.

sql {
        driver = "rlm_sql_postgresql"

        server = "localhost"
        login = "customer1"
        password = "password#"
        radius_db = "site1"

        authcheck_table = "vpn_users"
        authreply_table = "vpn_users"

        deletestalesessions = yes

        sqltrace = yes
        sqltracefile = ${logdir}/sqltrace.sql

        num_sql_socks = 1

        sql_user_name = "%{Stripped-User-Name:-%{User-Name:-none}}"

        authorize_check_query = "SELECT id, username, \
            'Crypt-Password' AS attribute, password, \
            '==' AS op \
            FROM ${authcheck_table} \
            WHERE username = '%{SQL-User-Name}'"

        authorize_reply_query = "SELECT id, username, \
            'Crypt-Password' AS attribute, \
            password, '==' AS op \
            FROM ${authreply_table} \
            WHERE username = '%{SQL-User-Name}'"
}

Cisco Changes

On the Cisco PIX/ASA you probably have inside, outside and perhaps dmz configured as your interfaces. Use the appropriate interface for launching RADIUS queries.

aaa-server RADIUS protocol radius 
aaa-server clientnet protocol radius 
aaa-server clientnet (inside) host 10.23.0.1 mysharedsecret timeout 10

References

GNU Radius IBM developerWorks

Build a RADIUS server on Linux

Practical PostgreSQL

Outbound RADIUS AAA Sample Configuration Guide for Cisco Secure ACS and PIX Firewall

Cisco - PIX Configuration basics altoHiway Knowledge Base