Two factor authentication with OTP using privacyIDEA and FreeRADIUS on CentOS
In this howto we will show, how you can set up a the two factor authentication and management system privacyIDEA on Cent OS 6.5. privacyIDEA is a system that can manage authentication devices - especially OTP tokens of any kind.
We will set up the system to be served via Apache2, store the token information in a MySQL database and provide authentication via FreeRADIUS server, thus being able to add two factor authentication to all services accessible via RADIUS like SSL VPNs and pam_radius.
Prerequisites
We need some special perl modules to run the connection between FreeRADIUS and privacyIDEA, which can be found in EPEL. So we need to install the EPEL repositories:
wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -Uvh epel-release-6*.rpm
Install dependencies
Install the necessary packages:
yum install -y mysql-server httpd mod_wsgi mod_ssl python-devel gcc mysql-devel libjpeg-devel freeradius freeradius-utils freeradius-perl openldap-devel perl-libwww-perl perl-Config-IniFiles perl-Try-Tiny perl-Data-Dump python-virtualenv
Configure the services to be started at bootup:
/sbin/chkconfig radiusd on
/sbin/chkconfig mysqld on
/sbin/chkconfig httpd on
Create database
Now we create a database privacyidea that will hold the token data. We choose the database password unknown:
/etc/init.d/mysqld restart
echo 'create database privacyidea;' | mysql
echo 'grant all privileges on privacyidea.* to "privacyidea"@"localhost" identified by "unknown";' | mysql
Create the virtual python environment and install privacyIDEA
privacyIDEA will be installed to a virtualenv at /opt/privacyIDEA. Thus we can use all the python modules that are needed and can simply backup the complete folder.
virtualenv /opt/privacyIDEA
Now we enter the virtual environment and install privacyIDEA:
cd /opt/privacyIDEA
source bin/activate
pip install privacyIDEA
pip install MySQL-python
Create config files
Still in the python virtualenv we create a service account and some config files:
mkdir -p /var/log/privacyidea
useradd -r privacyidea -d /opt/privacyIDEA
Create ini file
The ini file contains the configuration of the database and some other basic stuff. We copy the following file to /opt/privacyIDEA/etc/privacyidea/privacyidea.ini:
# privacyIDEA - Pylons development environment configuration # # The %(here)s variable will be replaced with the parent directory of this file # [DEFAULT] debug = false profile = false # Uncomment and replace with the address which should receive any error reports #email_to = you@yourdomain.com smtp_server = localhost error_email_from = paste@localhost # default audit trail set to SQL Audit privacyideaAudit.type = privacyidea.lib.auditmodules.sqlaudit privacyideaAudit.key.private = %(here)s/private.pem privacyideaAudit.key.public = %(here)s/public.pem #privacyideaAudit.sql.url = mysql://privacyidea:privacyidea@localhost/privacyidea #privacyideaAudit.sql.url = sqlite:///%(here)s/token.sqlite # One entry for SQL audit might take about 1K privacyideaAudit.sql.highwatermark = 10000 #privacyideaAudit.sql.lowwatermark = 5000 # If true, OTP values can be retrieved via the getotp controller privacyideaGetotp.active = True privacyideaSecretFile = %(here)s/encKey # This file contains the token administrators. # It can be created like this: # % tools/privacyidea-create-pwidresolver-user -u admin -p test -i 1000 >> config/admin-users privacyideaSuperuserFile = %(here)s/admin-users # list of realms, that are admins privacyideaSuperuserRealms = superuser, 2ndsuperusers privacyIDEASessionTimout = 1200 # This is the server, where this system is running. # This is need to issue a request during login to the # management with an OTP token. privacyideaURL = https://localhost # # This determines if the SSL certificate is checked during the login to # privacyIDEA. Set to True, if you have a self signed certificate. privacyideaURL.disable_ssl = False #privacyidea.useridresolver = privacyidea.lib.resolvers.PasswdIdResolver.IdResolver # This is only used for testnig purposes for running the selftests. #privacyidea.selfTest = True # These are the settings for the RADIUS Token # The location of the RADIUS dictionary file radius.dictfile= %(here)s/dictionary # The NAS Identifier of your privacyIDEA server, # that is sent to the RADIUS server radius.nas_identifier = privacyIDEA [server:main] use = egg:Paste#http #host = 172.16.200.100 host = 0.0.0.0 #host = localhost port = 5001 #ssl_pem = * [app:main] use = egg:privacyIDEA sqlalchemy.url = mysql://privacyidea:unknown@localhost/privacyidea #sqlalchemy.url = sqlite:///%(here)s/token.sqlite sqlalchemy.pool_recycle = 3600 full_stack = true static_files = true # We do not need a who.config, since we do the config in the # code at config/middleware.py #who.config_file = %(here)s/who.ini who.log_level = debug who.log_file = /var/log/privacyidea/privacyidea.log cache_dir = %(here)s/data custom_templates = %(here)s/custom-templates/ #beaker.session.key = privacyidea #beaker.session.secret = somesecret # If you'd like to fine-tune the individual locations of the cache data dirs # for the Cache data, or the Session saves, un-comment the desired settings # here: #beaker.cache.data_dir = %(here)s/data/cache #beaker.session.data_dir = %(here)s/data/sessions # # Note: You should change the Logging Level from DEGUB to WARN # # Logging configuration [loggers] keys = root, privacyidea, sqlalchemy #keys = root, privacyidea, sqlalchemy, controllers [logger_root] level = WARNING handlers = file [logger_privacyidea] level = INFO handlers = file qualname = privacyidea #[logger_controllers] #level = DEBUG #handlers = file #qualname = privacyidea.controllers.account [logger_sqlalchemy] level = ERROR handlers = file qualname = sqlalchemy.engine # "level = INFO" logs SQL queries. # "level = DEBUG" logs SQL queries and results. # "level = WARN" logs neither. (Recommended for production systems.) [handlers] keys = file [handler_file] class = handlers.RotatingFileHandler # Make the logfiles 10 MB # and rotate 4 files #args = ('%(here)s/privacyidea.log','a', 10000000, 4) # # Please note, that the %(here)s parameter will not work, when # running in wsgi. args = ('/var/log/privacyidea/privacyidea.log','a', 10000000, 4) level = INFO formatter = generic [formatters] keys = generic [formatter_generic] class = privacyidea.lib.log.SecureFormatter format = %(asctime)s %(levelname)-5.5s {%(thread)d} [%(name)s][%(funcName)s #%(lineno)d] %(message)s datefmt = %Y/%m/%d - %H:%M:%S
Create encryption key and signing keys
privacyidea-create-enckey -f /opt/privacyIDEA/etc/privacyidea/privacyidea.ini
privacyidea-create-auditkeys -f /opt/privacyIDEA/etc/privacyidea/privacyidea.ini
Create database tables
mkdir -p /var/log/privacyidea
paster setup-app /opt/privacyIDEA/etc/privacyidea/privacyidea.ini
Create admin user
Now we create the first admin user, that can log in to the privacyIDEA management:
privacyidea-create-pwidresolver-user -u admin -i 1000 >> /opt/privacyIDEA/etc/privacyidea/admin-users
Enter a password and remember it.
Setup Apache
privacyIDEA is a python application that is run via the WSGI module. This modules needs an additional run directory. We create it:
mkdir -p /var/run/wsgi
WSGI does not play well with SELinux. So for starters we need to disable the enforcing. In the file /etc/selinux/config we need to change this:
SELINUX=permissive
...and reboot the system to enable this.
After the reboot we again enter the virtualenv.
cd /opt/privacyIDEAy
source bin/activate
Apache config
In the apache directory /etc/httpd/conf.d we need to edit two files:
ssl.conf, which activates ssl:
LoadModule ssl_module modules/mod_ssl.so Listen 443 SSLPassPhraseDialog builtin SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000) SSLSessionCacheTimeout 300 SSLMutex default SSLRandomSeed startup file:/dev/urandom 256 SSLRandomSeed connect builtin SSLCryptoDevice builtin
and privacyidea.conf, which is the configuration of the virtual host.
A script will help you to create the server certificate:
privacyidea-create-certificate -f /etc/httpd/conf.d/privacyidea.conf
Fix access rights
During the setup process the files were generated for user root. But we will run privacyIDEA in Apache with the service account privacyidea. So we need to change the acccess rights of these files. A script helps us with this task:
privacyidea-fix-access-rights -f /opt/pirvacyIDEA/etc/privacyidea/privacyidea.ini -u privacyidea
Then we need to restart the apache service:
service httpd restart
Firewalling
The https port 443 might be closed. We can open it like this:
iptables -I INPUT 4 -p tcp --dport 443 -j ACCEPT
service iptables save
Now we can access the management UI via https on the server and create useridresolvers, a realm and enroll the first tokens. Another tutoral explains how to do this.
Setup FreeRADIUS
The privacyIDEA github repo contains a FreeRADIUS plugin, that is not yet contained in the privacyIDEA 1.1 release. So we need to copy it manually:
curl -o /opt/privacyIDEA/privacyidea_radius.pm https://raw.githubusercontent.com/privacyidea/privacyidea/master/authmodules/FreeRADIUS/privacyidea_radius.pm
Configuration
In the file /etc/radddb/users we need the following entry:
DEFAULT Auth-Type := perl
This sets the auth-type for every request to perl. Thus the request will be handled by the perl module.
Therefor the file /etc/raddb/modules/perl needs to look like this:
perl { module = /opt/privacyIDEA/privacyidea_radius.pm }
Remember to configure your file /etc/raddb/clients.conf according to your needs. You can at least add the localhost for testing purposes:
client 127.0.0.1/32 {
shortname = local
secret = topsecret
}
Finally we need to create a file /etc/raddb/sites-available/privacyidea, that in the importand sections authorize and authenticate looks like this:
authorize { preprocess chap mschap digest suffix eap { ok = return } files expiration logintime pap } authenticate { perl Auth-Type PAP { pap } Auth-Type CHAP { chap } Auth-Type MS-CHAP { mschap } digest unix eap }
(roughly we only added "perl" to the authenticate section ;-)
You can also download the file here.
We enable the site privacyidea by linking from sites-available to sites-enabled.
ln -s /etc/raddb/sites-available/privacyidea /etc/raddb/sites-enabled
We should delete the other sites in sites-enabled.
Testing RADIUS
To test the RADIUS configuration, we stop the FreeRADIUS and start it in debug output mode:
service radiusd stop
radiusd -X
Then we use the radclient command for testing:
echo "User-Name=user, Password=pin123456" | radclient -sx localhost auth topsecret
The output will display the total approved or denied auths.
In the FreeRADIUS ouput we can see a line like this for a successful authentication:
rlm_perl: privacyIDEA access granted
Questions? Answers!
If you run into any problems drop me a note or you can also ask on the Google group.