Note
These installation instructions assume you're installing on RHEL-6.
Start by installing the library files themselves. You can do that by installing the package provided by your distribution, or, if such package is not available, you can run:
python setup.py build python setup.py install
Next, create the secrets and state directories:
mkdir -p -m 0750 /etc/totpcgi/totp mkdir -p -m 0700 /var/lib/totpcgi
Next, create the user that the CGI will be running as:
useradd -M -s/sbin/nologin -d/var/lib/totpcgi totpcgi
Set the ownership on directories:
chgrp -R totpcgi /etc/totpcgi chown -R totpcgi /var/lib/totpcgi
To ensure that only trusted clients are allowed to talk to the server, you should configure mutual SSL authentication. For that, you'd need to generate a CA certificate, a server certificate, and a certificate for each of your clients.
Steps to do that can be found in many places on the web, so google for something like "sslverifyclient openssl genrsa" -- you should have a couple of decent hits.
Copy the certificates and keys as follows:
/etc/pki/tls/certs/totp-server.crt /etc/pki/tls/certs/totpcgi-ca.crt /etc/pki/tls/private/totp-server.key /etc/pki/tls/private/totpcgi-ca.key
Make sure the .key files are owned and readable by root only.
Hint
If you use puppet or func, you can reuse certificates generated by them. For puppet, the files are:
- /var/lib/puppet/ssl/ca/ca.pem
- /var/lib/puppet/ssl/private_keys/[your-server-hostname].pem
- /var/lib/puppet/ssl/certs/[your-server-hostname].pem
You can just use them directly in the httpd config file.
Hint
If you already have puppet-managed infrastructure, check out the puppet module and the quickstart doc in contrib/puppet!
Next, you'll need to install one of the CGIs.
Copy totp.cgi into /var/www/totpcgi/index.cgi and set the permissions:
mkdir -p -m 0551 /var/www/totpcgi cp -a cgi/totp.cgi /var/www/totpcgi/index.cgi chown -R totpcgi:totpcgi /var/www/totpcgi chmod 0550 /var/www/totpcgi/index.cgi
Create the config file in /etc/httpd/conf.d/totpcgi.conf using the vhost-totpcgi.conf template provided in contrib directory, and modify it accordingly to use FCGI instead of CGI.
Note
The default configuration runs on port 8443, as this makes it easier to deploy provisioning.cgi on the same host. It is up to you whether you want to use this configuration or not.
Nearly identical to what is above. The benefit of FastCGI is that it is quite a bit faster than CGI (as the name implies), without the extra overhead of starting another CGI process on each HTTP request hit. Though it is unlikely that your totpcgi server will see much traffic to really matter, if you are interested in avoiding performance problems, use FastCGI.
Start by installing mod_fcgid and flup:
yum install mod_fcgid python-flup
Next, copy the .fcgi in place, following the same procedure as .cgi:
mkdir -p -m 0551 /var/www/totpcgi cp -a cgi/totp.fcgi /var/www/totpcgi/index.fcgi chown -R totpcgi:totpcgi /var/www/totpcgi chmod 0550 /var/www/totpcgi/index.fcgi
Create the config file in /etc/httpd/conf.d/totpcgi.conf using the vhost-totpcgi.conf template provided in contrib directory, and modify it accordingly to use FCGI instead of CGI.
Note
Major thing to remember with .fcgi is that you will need to restart the server any time you make changes to the .fcgi file.
Yes, you really should. SELinux policy files come bundled in the tarball. Copy them over to the server and run:
sh totpcgi.sh
Warning
If you have modified any of the paths used above, you'll also need to modify the totpcgi.fc file and the totpcgi.sh file.
Totpcgi uses the same file format for TOTP secrets as files generated by google-authenticator, so if you already have some secrets generated with google-authenticator, just copy them into place:
cp ~/.google-authenticator /etc/totpcgi/totp/[username].totp chgrp totpcgi /etc/totpcgi/totp/[username].totp chmod 0440 /etc/totpcgi/totp/[username].totp
Alternatively, use the totpprov utility from the contrib/ directory. To install and use it, do the following:
cp conf/provisioning.conf /etc/totpcgi/
Edit the provisioning.conf file and change the "totp_user_mask" value to reflect your environment. After that, you should be able to run the following command to provision a user:
[root@totphost totpcgi]# totpprov generate-user-token wakka Generating new token for user wakka Are you sure [y/N]: y New token generated for user wakka otpauth://totp/[email protected]?secret=EBJVHOQTYVYIVMUG Scratch tokens: 23374296 25160754 86583002 93195170 32611388
You can pass this information to clients. To generate a QR code, you can install "qrencode" and run the following command with the otpauth:// URL returned by the totpprov command:
qrencode -s 5 -o totp-qrcode.png otpauth://totp/[...]
The "totpprov" utility doesn't set the token file ownership automatically, so the last thing you will need to do is set the ownership on the .totp file correctly:
chown root:totpcgi /etc/totpcgi/totp/wakka.totp chmod 0640 /etc/totpcgi/totp/wakka.totp
See "man totpprov" for more information on this utility, and don't forget to check out Provisioning CGI chapter.
First, create a SSL key and certificate for the client, and sign it with your CA key.
cp [your-client].crt /etc/pki/tls/certs/totpcgi.crt cp [your-ca].crt /etc/pki/tls/certs/totpcgi-ca.crt cp [your-client].pem /etc/pki/tls/private/totpcgi.pem
chown root:root /etc/pki/tls/private/totpcgi.pem chmod 0400 /etc/pki/tls/private/totpcgi.pem
Hint
If you are using puppet's SSL keys, you can just use them directly. They are in the following locations:
- /var/lib/puppet/ssl/certs/ca.pem
- /var/lib/puppet/ssl/certs/[your-client-hostname].pem
- /var/lib/puppet/ssl/private_keys/[your-client-hostname].pem
You are now ready to test to see if all is working right! Run the following command, replacing [username] and [token] with valid entries:
curl --cacert /etc/pki/tls/certs/totpcgi-ca.crt \ --cert /etc/pki/tls/certs/totpcgi.crt \ --data 'user=[username];token=[token];mode=PAM_SM_AUTH' \ https://totp.example.com:8443/
If all worked well, you should see:
OK
Warning
You shouldn't proceed to the next step unless the above test succeeds for you. You will lock yourself out of the system.
Install pam_url and create a configuration file in /etc/pam_url.conf as provided in the contrib directory.
Now you need to add it to your pam configuration. Let's change it so users can sudo with their Google-Authenticator token. Edit /etc/pam.d/sudo and add this line above all other auth lines:
auth sufficient pam_url.so config=/etc/pam_url.conf
Alternatively, see other pam examples in the contrib directory.
If you've ever used RSA tokens, you'll know that they support user pins in addition to numeric tokens. This functionality is duplicated in totpcgi. To enable it, you'll need to tweak a number of things.
First, create /etc/totpcgi/pincodes. The file format is the same as /etc/shadow, except we only pay attention to the first 2 parts (username:password-hash). Totpcgi supports sha-512 and sha-256 password hashes, so some tools exist that can help you manage that file just like an /etc/shadow file.
Alternatively, you can maintain the file on your own using bcrypt hashes. To generate a bcrypt hash, install py-bcrypt and run:
python -c "import bcrypt; print bcrypt.hashpw('pincode', bcrypt.gensalt())"
Warning
Any time you specify passwords on command line like that, they will be viewable in "ps" and stored in your .bash_history.
Warning
You should NOT use the same pin as the user system password, at least as long as you're using the file-based backend.
Make sure you set the right permissions on the pincodes file:
chown root:totpcgi /etc/totpcgi/pincodes chmod 0640 /etc/totpcgi/pincodes
You should now be able to log in using pincode+tokencode. E.g. if you set your pincode to 'secret' and your token is 555555, you enter 'secret555555'. You should be able to use that the moment the pincodes file is in place.
You will now need to adjust /etc/totpcgi/totpcgi.conf to require that pincodes are used:
[main] require_pincode = True
The following PAM settings for sudo will require your users authenticate with their Pincode+Token:
#%PAM-1.0 auth required pam_env.so auth sufficient pam_url.so config=/etc/pam_url.conf auth requisite pam_succeed_if.so uid >= 500 quiet auth required pam_deny.so account include system-auth password include system-auth session optional pam_keyinit.so revoke session required pam_limits.so
You can additionally adjust the sshd pam configuration to do the same -- look in the contrib directory for it. Keep in mind, that when public key authentication is used, it completely bypasses pam.
Once you require the use of pincodes, you may consider using them to encrypt the master secrets used to generate TOTP codes. This gives you extra protection in case something happens and someone is able to read the contents of your TOTP secrets (for example, by getting access to your backups). Without knowing the users' pincodes, it would be impossible to decrypt the secrets.
It's important to realize that this comes with a trade-off -- if a client forgets their pincode, the TOTP token will need to be re-provisioned.
Encryption needs to be done during the provisioning stage. If the administrator provisions the tokens manually, they can use the "totpprov" utility in the contrib directory to encrypt existing secrets. If some other process is used, you should rely on the implementation in that file to generate encrypted secrets that totpcgi can handle.
Warning
One-time scratch tokens are completely ignored by totpcgi when encrypted secrets are used, as doing otherwise would defeat the point of encrypting the master secret.
If you want to use a load-balanced configuration, you will need to save the state files in a central database.
Warning
DO NOT use the File state backend in a multiple-server setup. This will make you vulnerable to token reuse, as one server will not know that the token was already presented to the other server.
Running databases is a complex task, but this is a quick guide. First, install postgresql-server:
yum install postgresql-server
Now init the database and start the server:
service postgresql initdb service postgresql start
Now create the database and tables using the provided file. First, though, edit totpcgi.psql and adjust the password to a non-default value.
To create and populate the database, run:
su -l postgres createdb totpcgi psql totpcgi < totpcgi.psql
Now you need to edit /var/lib/pgsql/data/pg_hba.conf and add the following line before all the "all" lines:
host totpcgi totpcgi your.subnet/24 md5
Restart the server:
service postgresql restart
Now, install python-psycopg2 on your totpcgi servers:
yum install python-psycopg2
Now modify /etc/totpcgi/totpcgi.conf and enable the postgresql state backend:
[state_backend] engine = pgsql pg_connect_string = user=totpcgi password=wakkawakka host=localhost dbname=totpcgi
Restart the http server if you're using FastCGI. Make sure your iptables rules on the server allow incoming postgresql traffic.
Note
You can also use postgresql for your secrets and pincodes backend. If you use "totpprov" or provisioning.cgi, it will read the configuration from /etc/totpcgi/provisioning.conf and know where to put the provisioned information.
You can use a LDAP directory for your pincode backend -- the CGI will validate pincodes by trying to bind to the LDAP server using the provided credentials. To enable the LDAP pincode backend, modify /etc/totpcgi/totpcgi.conf and set the following:
[pincode_backend] engine = ldap ldap_url = ldaps://ldap.example.com:636/ ldap_cacert = /etc/pki/tls/certs/ca.crt ldap_dn = uid=$username,cn=users,cn=accounts,dc=example,dc=com
The ldap_dn listed above is for use with FreeIPA -- you will need to modify it to reflect the valid DN for your users. The "$username" entry will be replaced by whatever the authenticating clients provide as their username (or, when using sudo, the username will be their current system usersname).
Configuring LDAP is way beyond this document, so I leave this task up to you. If you've never done it before but would like to try, I suggest you look at FreeIPA (in RHEL6.2 and above as "ipa-server").
Starting with version 0.5, we include full support for provisioning tokens. You can use the provisioning.cgi that ships with the project for user-initiated provisioning, or you can use it as an example implementation in order to incorporate provisioning support into your existing web infrastructure.
Note
Provisioning CGI requires that pincodes are used, otherwise there is no way to authenticate the user that logs in to obtain the token. Alternatively, use trust_http_auth option and authenticate users on the apache level.
Start by installing the CGI and configuration files:
mkdir -p -m 0551 /var/www/totpcgi-provisioning cp -a cgi/provisioning.cgi /var/www/totpcgi-provisioning/index.cgi cp -a cgi/*.css /var/www/totpcgi-provisioning/ chmod 0550 /var/www/totpcgi/index.cgi
To only allow the provisioning.cgi to modify .totp files, we will need to set up provisioning.cgi to run as a separate user from totp.cgi. Let's start by creating that user:
useradd -M -s/sbin/nologin -d/var/lib/totpcgi totpcgiprov
Now we'll need to adjust the ownership on directories:
chown totpcgiprov:totpcgi /etc/totpcgi chown totpcgiprov:totpcgi /var/lib/totpcgi chmod 0770 /var/lib/totpcgi chmod 0666 /var/lib/totpcgi/*.json chown -R totpcgiprov:totpcgi /etc/totpcgi/totp chown -R totpcgiprov:totpcgiprov /var/www/totpcgi-provisioning
Now copy conf/templates into /etc/totpcgi/templates. You want to edit the .html files in the templates directory to your liking, unless you work for Example Company, LTD. Review the settings in /etc/totpcgi/provisioning.conf as well, to make sure the defaults are sane.
Configuring Apache is going to be less straightforward. To run these two CGIs as two different users, we'll need to create two separate VirtualHost entries, but this becomes tricky with SSL:
These two VirtualHosts must have different hostnames and run on separate IPs, in which case:
- You must use a wildcard certificate that is correct for both hostnames
- You must use a certificate with a host alias that is correct for both hostnames
These two VirtualHosts can run on the same IP, but listen on different ports
The default configuration uses the 2nd scenario -- we run totp.cgi on port 8443, since it's not a user-visible address, and the provisioning cgi on the standard https port 443. It is entirely up to you how you make it work in your environment.
To use the default scenario, copy the vhost-totpcgi-provisioning.conf from the contrib directory into /etc/httpd/conf.d/totpcgi-provisioning.conf and edit accordingly to use the right hostname and SSL certificates.
Restart httpd, and see if everything is working right.
The only way to use totpcgi with web services is via mod_auth_pam or mod_authnz_auth -- either directly on the Apache host, or via a SSO solution, such as CAS, Webauth or Pubcookie.
If someone feels like contributing a native module for any of these services, that initiative will be welcomed. :)