Skip to content

Use Yubikey and Password-store for Ansible credentials

I spent some time over the last months to improve the security of servers and passwords. In doing so, I started to orchestrate my servers using a configuration management tool called Ansible. This allows me to spin-up fresh servers in a few seconds and to get rid of year-old, polluted and insecure system images.

Ansible loves Yubico
Ansible loves Yubico.

My ‘single password for everything’ has been replaced by a new password policy which enforces individual passwords for every single service. This was easier than I previously expected:

To unlock the ‘paranoid’ level, I additionally purchased a Yubikey Neo token to handle the decryption of my login credentials in tamper-proof hardware. ‘pass’ is just a small shell script to glue several existing Unix tools together: Bash, pwgen, Git, xclip & GnuPG (obeying the Unix philosophy). The passwords are stored in simple text files which are encrypted by PGP and stored in a directory structure which is managed in a Git repository.

Yubikey Neo und Neo-n
Yubikey Neo und Neo-n.

There are already a tons of tutorials which present the tools I describes above. I do not want to repeat all of it. So, this post is dedicated to solve some smaller issues I encountered.

Use One-Time passwords across multiple servers

Section titled “Use One-Time passwords across multiple servers”

The Yubikey Neo can do much more than decrypting static passwords via GnuPG:

  • Generate passwords:
    • fixed string (insecure!)
    • with Yubico OTP algorithm
    • with OATH-HOTP algorithm
  • Do challenge response authentication
    • via FIDO’s U2F standard
    • with HMAC-SHA1 algorithm
    • with Yubico OTP algorithm

Some third-party services already support FIDO U2F standard or traditional OATH-{H,T}OTP TFA, like used by the Google authenticator app. I suggest to have a look at: https://twofactorauth.org.

For private servers there are several PAM modules available to integrate OTP’s or Challenge Response (CR) methods. Unfortunately, support for CR is not widespread across different SSH- and mail clients.

So, you want to use OTP’s which leds to another problem: OTP’s rely on a synchronized counter between the hardware token and the server. Once you use multiple servers, those must be synchronized as well. I’m using a central Radius server to facilitate this.

Ansible uses SSH and Python scripts to manage several remote machines in parallel. You must use key-based SSH authentication, because you do not want to type every password manually! Additionally you need to get super user privileges for most of your administrative tasks on the remote machine.

The SSH authentication is handled by gpg-agents --enable-ssh-support option and a PGP key on your token.

To get super user privileges, I use the following variable declaration my Ansible group_vars/all file:

---
ansible_sudo_pass: "{{ lookup('pipe', 'pass servers/' + inventory_hostname) }}"

There is a separate root password for every server (e.g. pass servers/lian.0l.de). I wrote some Ansible roles to easily and periodically rotate these passwords.

There are already several plugins and extensions to integrate the pass password store into other Programs like Firefox and Android.

A prompt for the password you want
A prompt for the password you want.

I added support for OS X by writing a small AppleScript which can be found here: /zx2c4/password-store/contrib/pass.applescript .

A notification with countdown
A notification with countdown.