Installing LinOTP2 on Rocky 8
Cet article est également disponible en français : Installation LinOTP2 on Rocky 8.
Hello,
Today we will install the latest LinOTP2 release from source on a Rocky 8 server in a Python 2 virtualenv. We are going to setup a basic LinOTP server for time-based OTP tokens (those used by Google Authenticator) and configure FreeRADIUS to enable RADIUS authentication. Let’s start.
LinOTP install
At the time of writing this tutorial, LinOTP developers don’t provide RPM for Rocky 8, you are limited to CentOS 7 or outdated pypi packages (the last update is almost 2 years old). So we’ll install it from the latest git version (currently 2.12.3).
You must first install python2, OpenSSL development package, swig and gcc from Rocky repositories. The 3 last packages are needed to install m2crypto Python package from pip later in this tutorial :
dnf install epel-release
dnf install python2 python2-wheel python2-virtualenv git openssl-devel swig gcc openldap-devel libsodium
Create a virtualenv in /srv and activate it :
cd /srv/
virtualenv-2 linotp
cd /srv/linotp
. bin/activate
Install required Python dependencies from pypi :
pip install pillow pillow-pil m2crypto
Clone the official github repository :
git clone https://github.com/LinOTP/LinOTP
Now you must find the latest stable release from git repository tags. Each release has an associated tag starting with release/ :
cd LinOTP
STABLE_VERSION=$(git tag | grep release/2 | cut -d/ -f2 | sort --version-sort | tail -1)
git checkout release/$STABLE_VERSION
You must be in the activated virtualenv for the next commands. To install LinOTP and LinOTP admin CLI in your virtualenv, you would just run setup.py install but it will not work because missing dependencies will be downloaded in their latest version instead of their latest Python2 compatible version. The workaround is to build a wheel package that you install with pip, so pip will download the correct requirements versions :
cd /srv/linotp/LinOTP/linotpd/src/
python2 setup.py bdist_wheel
pip install dist/LinOTP-${STABLE_VERSION}-py2-none-any.whl
cd /srv/linotp/LinOTP/adminclient/LinOTPAdminClientCLI/src
python2 setup.py bdist_wheel
pip install dist/LinOTPAdminClientCLI-${STABLE_VERSION}-py2-none-any.whl
LinOTP is now installed in your virtualenv, but you have a few more manual steps to complete to finish installation. Create configuration directory, copy an example linotp.ini file and generate the secret that will be used to encrypt tokens secrets in the database :
useradd -d /srv/linotp -r -s /sbin/nologin linotp
mkdir -pv /etc/linotp2/data
mkdir -pv /var/log/linotp/
cp /srv/linotp/etc/linotp2/linotp.ini.example /etc/linotp2/linotp.ini
linotp-create-enckey -f /etc/linotp2/linotp.ini
chown linotp:linotp -R /etc/linotp2
chown linotp:linotp -R /var/log/linotp
All done! You’ve successfully installed and configured your LinOTP service.
MariaDB
LinOTP uses SQL Alchemy ORM library to access its database. It enables you to choose your preferred database, from SQLite to PostgreSQL. In this tutorial you’ll use MariaDB server because it’s well-known and easy to setup.
Install MariaDB package :
dnf install mariadb-server
Enable and start the service :
systemctl enable --now mariadb
Secure installation (removing test database and setting a root password) :
mysql_secure_installation
Create the LinOTP database with its associated user :
mysql -p
CREATE DATABASE linotp;
GRANT ALL PRIVILEGES ON linotp.* TO linotp@localhost IDENTIFIED BY 'PASSWORD';
Install pymysql package in your virtualenv in order to enable SQL Alchemy to connect to your database :
pip install pymysql
Now, configure the database access in the configuration file. Edit /etc/linotp2/linotp.ini
with your favorite editor.
Replace the following line with the database settings (if you have chosen different database name and login change the configuration accordingly):
sqlalchemy.url = mysql+pymysql://linotp:PASSWORD@localhost/linotp
Initializing and testing LinOTP
LinOTP is installed, your database is ready, now you can create the database structure with the following command :
su linotp -s /bin/bash -c "paster setup-app /etc/linotp2/linotp.ini"
You can check that everything is right now with :
su linotp -s /bin/bash -c "paster serve /etc/linotp2/linotp.ini"
LinOTP service administration page should be available at http://localhost:5001/manage/
Configuring Apache HTTPD
In a production environment you must not use the LinOTP’s builtin HTTP server. As you have seen previously the administration web interface is open to everybody without authentication. You have to configure an Apache HTTP frontend that will use WSGI to serve LinOTP application and enable authentication configuration.
Start by installing httpd and its development package. You will use the later to compile python2 mod_wsgi Apache module with pip command.
dnf install httpd httpd-devel mod_ssl
pip install mod_wsgi
Create a symlink to mod_wsgi module in httpd module directory :
ln -s /srv/linotp/lib/python2.7/site-packages/mod_wsgi/server/mod_wsgi-py27.so /etc/httpd/modules/
Add an httpd configuration file to load wsgi module :
cat > /etc/httpd/conf.modules.d/99-wsgi.conf <<EOF
LoadModule wsgi_module modules/mod_wsgi-py27.so
EOF
Replace /etc/httpd/conf.d/ssl.conf
content with a secure configuration that only allows TLS 1.2+ connections :
# Generated from https://ssl-config.mozilla.org/#server=apache&version=2.4.37&config=modern&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off
Apache will use a WSGI python script to load the application, copy it to /etc/linotp2/
and copy the example LinOTP virtual host configuration file to httpd configuration directory :
cp /srv/linotp/etc/linotp2/linotpapp.wsgi /etc/linotp2/
cp /srv/linotp/LinOTP/linotpd/src/config/apache2.4-example/linotp2.conf /etc/httpd/conf.d/
Edit the copied linotp2.conf to replace Include /etc/linotp2/apache-servername.conf
by ServerName YOUR_DOMAIN
On the following line change python-home
directory to your installation directory (/srv/linotp
) :
WSGIDaemonProcess linotp processes=1 threads=15 display-name=%{GROUP} user=linotp python-home=/srv/linotp
Secure web interface access with your preferred authentication method, in the default linotp2.conf a file-based digest authentication is used :
AuthType Digest
AuthName "LinOTP2 admin area"
AuthDigestProvider file
AuthUserFile /etc/linotp2/admins
Require valid-user
Change SSL certificate location near the end of the file :
SSLCertificateFile /etc/linotp2/linotpserver.pem
SSLCertificateKeyFile /etc/linotp2/linotpserver.key
Add an admin account in the /etc/linotp2/admins
:
htdigest -c /etc/linotp2/admins admin
Generate a self-signed certificate (or use your own trusted certificate) :
openssl req -subj '/CN=172.24.12.168' -new -newkey rsa:2048 -sha256 -days 3650 -nodes -x509 -keyout /etc/linotp2/linotpserver.key -out /etc/linotp2/linotpserver.pem
Change log path :
ErrorLog logs/error_log
CustomLog logs/ssl_accessa_log LinOTP2
Start httpd server :
systemctl enable --now httpd
Configuring RADIUS
A common usage of OTP tokens is to allow other applications to validate a second authentication factor through the RADIUS protocol. Many software and hardware components support RADIUS authentication (VPN Gateways, switches, Citrix Netscaler, …). LinOTP provides a PERL module that can be used by FreeRADIUS to call LinOTP service for authentications.
Start by installing FreeRADIUS and some needed PERL packages :
dnf install freeradius-perl cpan
cpan install LWP Config::File LWP::Protocol::https
Download the LinOTP PERL module from GitHub and save it to your installation directory :
curl https://raw.githubusercontent.com/LinOTP/linotp-auth-freeradius-perl/master/radius_linotp.pm -o /srv/linotp/share/linotp/radius-linotp.pm
Configure FreeRADIUS LinOTP module :
cat >/etc/raddb/mods-enabled/perl-linotp <<EOF
perl linotp {
filename = /srv/linotp/share/linotp/radius-linotp.pm
perl_flags = "-T"
}
EOF
Remove unused default sites :
rm /etc/raddb/sites-enabled/*
Create a LinOTP site with the minimal working configuration :
cat >/etc/raddb/sites-enabled/linotp <<EOF
server linotp {
listen {
type = auth
ipaddr = *
# 0 means "use /etc/services for the proper port"
port = 0
}
authorize {
filter_username
preprocess
suffix
update control {
Auth-Type := PAP
}
}
authenticate {
Auth-Type PAP {
linotp
}
}
}
EOF
You can use radius -X
to check that the service is working, then systemctl enable --now radiusd
Quick test
Now that every component is configured and running you can perform a quick test.
Create a flat file user ID resolver based on the /etc/passwd file so you can create a token for a local user, then create a realm that uses your user ID resolver. You can now navigate to the user tab and enroll a time-based OTP token for the root user. Scan the QRCode with an OTP application and try it with the radtest command (package freeradius-utils) :
radtest root YOUR_TOTP_TOKEN_VALUE 127.0.0.1 1
You should get an Access Granted response, otherwise you can debug what happened by stopping freeradius service, running radius -X
and looking at /var/log/linotp/linotp.log.
Upgrading
Upgrade can be done by pulling the latest version from the git repository and generating the new wheel package using the pip commands you saw above.
Then you need to update the packages in your virtualenv using pip install --upgrade /path/to/newversion.whl
. Read the release note to check if you have any other commands to run before or after the packages updates.