Google Authenticator with SaltStack


I’ve been working with SaltStack for a few weeks now and am becoming a fan. I’ve written a fair amount of both Puppet and Ansible and know it’s not so simple to get started with either.

Puppet’s DSL is daunting to some people so the alternative to writing configuration management code defaults to Ansible because of it’s popularity. Some say Ansible is easier to understand, but introduces a suspicious lock-in factor… You be the judge.

My opinion…

In a nutshell, compared to Puppet and Ansible, Salt is the best of both worlds without a huge time and financial investment. You get the simplicity of writing configuration management code in YAML yet not bound by a full DSL and have all the power of Python. With that said, I don’t want to get into a full side-by-side-by-side comparison of these three tools. There are plenty of comparisons out there to let you decide which is right for the task at hand. I’m just gonna show you how easy it is with Salt.

Using Augeas to manage PAM

I’ve jumped on the MFA band wagon (and you should too) and started using Google Authenticator for SSH. Atfirst, it seemed like it wasn’t ready for prime time for CentOS. I read a few blog posts about how to set Google Authenticator up and they all used a Debian flavor OS because the PAM module is neatly packaged and available though standard repositories. Not CentOS… What I read used a tarball of the source code, locally compiled and installed using the install method of the Makefile. I really wanted to enable CentOS’ default package management system to handle the PAM module install so I built my own RPM. Which is simpler than it sounds, It’s all detailed here.

After a successful rpmbuild, I had a shiny new RPM package, with the possibility of being managed by yum, that was installable without having to install compilation tools which having available pose a security risk.

Using Salt, I was able to use the built-in package management state module to install the PAM module. Win!

Now off to configuration…

I’m not gonna detail how to setup a Salt master environment here, there are plenty of resources out there to help you with all the different options that are right for you. Let’s just assume you have a master and are able to orchestrate the highstate on your minions.

Augeas is pretty much the de facto standard in most configuration management tools to handle updates to any text based configuration files. Not surprising to see Salt is embracing this method and look forward to full support.

The code below should modify /etc/pam.d/sshd to insert the pam_google_authenticator.so module line after the pam_sepermit.so line and remove the password-auth line since I don’t use password authentication. You may want to consider leaving the password-auth line if you actually use password authentication.

pam_ins_google_authenticator:
  augeas.change:
    - context: /files/etc/pam.d/sshd
    - changes:
      - ins 999 after "*[type = 'auth'][control = 'required'][module = 'pam_sepermit.so']"
      - set 999/type auth
      - set 999/control required
      - set 999/module pam_google_authenticator.so
    - unless: grep -Eq '^auth[[:blank:]]*required[[:blank:]]*pam_google_authenticator.so$' /etc/pam.d/sshd

pam_rm_password-auth:
  augeas.change:
    - context: /files/etc/pam.d/sshd
    - changes:
      - rm "*[type = 'auth'][control = 'substack'][module = 'password-auth']"
    - onlyif: grep -Eq '^auth[[:blank:]]*substack[[:blank:]]*password-auth$' /etc/pam.d/sshd

I also needed to make a few adjustments to /etc/ssh/sshd_config

The code below should insert (or update) two lines in /etc/ssh/sshd_config that control SSH support for keyboard-interactive authentication. You need this to allow sshd to prompt for the validation code needed by the Google Authenticator service. Again, I use publickey authentication and not password so you may need to adjust the AuthenticationMethods to your environment.

sshd_config_enable_ChallengeResponse:
  augeas.change:
    - context: /files/etc/ssh/sshd_config
    - changes:
      - set ChallengeResponseAuthentication yes
    - unless: grep -Eq '^ChallengeResponseAuthentication yes$' /etc/ssh/sshd_config
    - watch_in:
      - service: sshd

sshd_config_enable_AuthenticationMethods:
  augeas.change:
    - context: /files/etc/ssh/sshd_config
    - changes:
      - set AuthenticationMethods publickey,keyboard-interactive
    - unless: grep -Eq '^AuthenticationMethods publickey,keyboard-interactive$' /etc/ssh/sshd_config
    - watch_in:
      - service: sshd

Now run salt to apply the highstate to the minion. Assuming you’ve created additional states to manage the package install, this should configure PAM and sshd properly.

**

PAM and sshd is configured… Now what?

**

Fantastic! You just need to run the configuration of an MFA for any local user using this command:

google-authenticator -tdf --rate-limit=3 --rate-time=30 --window-size=17

And scan the QR code.

The resulting ~/.google_authenticator file can be managed using Salt but should be treated as sensitive information stored on disk.