Monday, 9 June 2014

Maverick Adventures with Google Authenticator

Please note, this article assumes you're somewhat familiar with running commands in a terminal and editing system files. If you are not comfortable with this, I'd suggest you don't particularly want to mess around with these things just yet.

Today I decided to improve the login security for my OS X install with the use of 2-factor authentication with the Google Authenticator PAM. Turns out there's not much information on this, and what is there neglects some interesting steps, so I'll write up my own experience here in the hope that it'll help someone.

First, download the code from

Extract it and in the directory run make && sudo make install. This will compile the PAM library and the command line tool for creating your secret. It will also put the command line tool in the correct place of /usr/local/bin and the PAM library in the wrong place of /usr/lib

So, now we put the library in the correct place with mv /usr/lib/ /usr/lib/pam/

The library is now installed, so now it's onto config. At this point, it's possible to lock yourself out, so it would be really smart to make sure you have SSH turned on for your mac and have another machine to SSH in from handy... just in case (n.b. I didn't do this. I then had to figure out how to unmangle my PAM file to login again... you don't want to have to do this).

If you want, you can also install the qrencode library, which will allow a QR code to be generated in the next step. With homebrew, this is brew install qrencode

First part of the config is generating your authenticator secret. Run the command line tool google-authenticator. This will generate a secret and a set of backup tokens. It will also ask you a few questions, answer as appropriate.

Now you get to decide what services will use 2-factor authentication. I went for SSH, sudo, login and unlock, which involved the PAM files authorization, login, screensaver, sudo and sshd (all in the /etc/pam.d directory). The configs for these are as follows:

In each of the files, the important modifications are around the line
auth required

This line, and the options following it, insert the google authenticator PAM into your authentication chain. With SSH and sudo, this is done with a 'challenge-response' prompt, where it will ask you for a verification key. However, the OSX login lacks this ability to insert another prompt, so for logging in or unlocking the screen, we use the forward_pass option, which expects the password and TOTP to be provided together as <password><totp>. This may cause your keychain login to complain about an incorrect password - do not change the password unless you want to write down the token when you logged in so you can remember the password next time. Instead, when you have finished logging in, the keychain will prompt for your password again. Type it in normally and you're all set.

If you wanted, you could also try the following for sudo:

# sudo: auth account password session
auth sufficient
auth required
account required
password required
session required

This will alter your sudo authentication so that you will be prompted for a TOTP first. If this is correct then sudo authentication succeeds. If it fails, it will fall back to the traditional asking for a password.

Tuesday, 4 February 2014

Encrypted Chef Node Data

When dealing with Chef, you frequently want to store data in an encrypted form so that your Chef Server doesn't become a single point of vulnerability for the security of your entire infrastructure. For this purpose, Chef has the concept of an Encrypted Data Bag.

Also when dealing with Chef, you frequently want to generate certain bits of data and remember them for future runs. When dealing with a Chef Server, you also sometimes want to let other nodes grab this data for their own configuration. For this, you have standard, plain text Node data.

So what happens when you want to generate something that needs to be kept secure, such as the passwords for your database users? You could put them in an Encrypted Data Bag, but then you need to generate this data in advance. You could put them in the node data, but then your passwords are stored in plaintext on the Chef Server.

Neither of these solutions are ideal. What we want is to be able to generate the data on the node and store it in an encrypted form. Unfortunately, Data Bags can't be updated during a run (and this does lead to some race conditions, as what would happen if several nodes tried to update the same data bag at the same time? Distributed race conditions are never fun).

How about encrypting the data in the node though? This seems like a good approach, as the node data is safe(ish) from distributed race conditions, but it would be fairly tedious to have to build our own encryption mechanism for nodes, so maybe we can re-use some of the encryption used for Encrypted Data Bags? This is surprisingly easy to do, as the data bag encryption is well factored into code for Secrets, Encryptors and Decryptors separately from the main Encrypted Data Bag code that binds them together (although the namespace doesn't lead to the clearest code at this point).

Without belabouring the point too much, by placing something like this:

into libraries/node_encryption.rb in a cookbook, you can then make use of this in your recipe in the following way:

This does still rely on your secret being shared between your servers, in the same way as Encrypted Data Bags, so it isn't perfect. Our own infrastructure makes use of multiple sets of secrets in order to mitigate this on an environment basis (the secrets for our development servers are separate from the ones for our production environment). What would be really fun would be if this could be integrated into a tool like Chef-Vault (see also this blog post on chef-vault),  so you could generate a value on a node and specify a search to specify which nodes are allowed to decrypt the value. This would extend the usefulness of Chef-Vault a bit, as you could then rely on your cookbooks to handle some of the re-encrypting that currently needs to be done manually with Chef-Vault (such as re-encrypting a value when a new node is added to grant access with the new node's public/private keypair).