Bootstrapping a new FreeBSD jail host as an Ansible node

A few days I configured a new server to be an Ansible node. This will allow my Ansible configuration tool to configure and install software.

Installing Ansible and getting it running is not covered by the post. All I show here is how I got a remote server ready to be configured by Ansible.

The server in question was running FreeBSD 9.2 with ZFSRoot.

Preparing the client for configuration by Ansible

Key to how Ansible works is ssh. Ansible also needs root access. Rather than allowing root to ssh in, which is never a good idea, I created a user specifically for running Ansible. This user will be the same on all hosts and it will have sudo access. The sudo authentication will be via ssh-agent. I got my start on this path by talking with the highly respected and knowledgable Michael W. Lucas.

Here are the steps I am about to describe:

  1. create the ansible user
  2. add ~/.ssh/authorized_keys file for that user
  3. install tools required by ansible
  4. configure ssh-agent auth for sudo

Allow only ssh-key logins, no passwords

I will allow only ssh-key logins on this host. I specify that by adding this to /etc/ssh/sshd_config

PasswordAuthentication          no
ChallengeResponseAuthentication no

After making that change, you need to restart sshd:

service sshd restart

You can test the login, without a key, and it should look like this:

$ ssh yourhost.example.com
Permission denied (publickey).

Now that we allow only ssh-key logins, let’s create our special user.

Create the ansible user

It does not matter what user you create. The actual login name is not important. I picked ansible and created it with this command:

pw useradd -n ansible -s /bin/sh -m -d /usr/home/ansible -G wheel

The user is in the wheel group, so it can use sudo based on the criteria I specify later.

Add ~/.ssh/authorized_keys

Next, I create the .ssh directory:

mkdir /usr/home/ansible/.ssh
chown ansible:ansible /usr/home/ansible/.ssh
chmod 0700 /usr/home/ansible/.ssh

I had already created a set of ssh-keys for this user. The public key was then copied to this file:

/usr/home/ansible/.ssh/authorized_keys

The permissions were set accordingly:

chown ansible:ansible /usr/home/ansible/.ssh/authorized_keys
chmod 0600            /usr/home/ansible/.ssh/authorized_keys

At this point, the ansible user should be able to login via ssh.

But before you login for the first time!

The safe approach is always to know your server’s ssh fingerprint before connecting. Make sure the output of this command, issued on the server in question:

# ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub
256 bf:f1:ad:8d:0f:99:fb:fb:49:f6:5c:e9:70:0b:87:ae /etc/ssh/ssh_host_ecdsa_key.pub (ECDSA)

… matches what you see here when you first connect:

# ssh -A ansible@10.1.1.10
The authenticity of host '10.1.1.10 (10.1.1.10)' can't be established.
ECDSA key fingerprint is bf:f1:ad:8d:0f:99:fb:fb:49:f6:5c:e9:70:0b:87:ae.
Are you sure you want to continue connecting (yes/no)? yes

Install tools required by Ansible

There are a few tools required by Ansible. Let’s get them installed. These commands are suitable for unattended installs (i.e. you will not be prompted):

env ASSUME_ALWAYS_YES=YES pkg bootstrap

pkg install -y sudo
pkg install -y python
pkg install -y security/pam_ssh_agent_auth
pkg install -y ca_root_nss

Next, run visudo to allow wheel to run sudo, by making sure this line is uncommented:

%wheel ALL=(ALL) ALL

FYI, I install ca_root_nss because it helps with certificate authentication when fetching patches over https.

Configure ssh agent auth for sudo

In this step, I relied heavily upon Mr Lucas’ blog post on sudo auth via ssh-agent.

The only major difference between his setup and mine is this line at the head of /usr/local/etc/sudoers. Run visudo to add this line:

Defaults env_keep += "SSH_CLIENT SSH_CONNECTION SSH_TTY SSH_AUTH_SOCK",timestamp_timeout=0

In this section, I will tell sudo how to authenticate commands it is given.

My /usr/local/etc/pam.d/sudo file contains this:

auth sufficient /usr/local/lib/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys
auth required pam_deny.so
account include system
session required pam_permit.so

Any user in the wheel group should now be able to use sudo without typing their password, provided they are logged in with an ssh-key contained in ~/.ssh/authorized_keys. The authentication process will consult their ssh-agent.

That’s all folks!

Now your chosen Ansible user should allow you to connect and configure!

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive

6 thoughts on “Bootstrapping a new FreeBSD jail host as an Ansible node”

  1. Thanks for this article, I ended up changing this line

    auth sufficient /usr/local/lib/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys

    to use a separate file:

    auth sufficient /usr/local/lib/pam_ssh_agent_auth.so file=/root/.ssh/sudo_authorized_keys

    Since the ed25519 keys in ~/.ssh/authorized_keys for ssh authentication do not work with this pam module,
    as it only supports the older rsa and dsa keys.
    I opted have dsa keys in the root owned file for sudo auth, which also allows for a different passphrase to be used.

  2. Hi Dan,

    Great post. Based on what you’ve posted and whats in the new version of ansible I’ve put this together as a rough cut. I didnt create a different user but it could be easily extended to do that as well.

    ---
    # freebsd requires some extra config to get ansible working
    - hosts: cdas
      remote_user: root
      become: yes
      become_method: su
      gather_facts: False
      vars:
        ansible_python_interpreter: "/usr/local/bin/python"
    
      tasks:
      - name: Install python with raw as ansible relies on it for most commands except raw
        raw: pkg install -y python
    
      - name: install packages
        pkgng: name={{item}} state=present
        with_items:
          - sudo
          - security/pam_ssh_agent_auth
          - ca_root_nss
    
      - name: Copy sudoers file for safety
        command: cp -f /usr/local/etc/sudoers /usr/local/etc/sudoers.tmp
    
      - name: Create sudoers file backup
        command: cp -f /usr/local/etc/sudoers /usr/local/etc/sudoers.bak
    
      - name: now add items so that ansible can run sudo commands
        lineinfile: dest=/usr/local/etc/sudoers.tmp state=present line='{{item}}'
        with_items:
          - 'ec2-user ALL=(ALL) NOPASSWD: ALL'
          - 'Defaults env_keep += "SSH_CLIENT SSH_CONNECTION SSH_TTY SSH_AUTH_SOCK",timestamp_timeout=0'
    
      - name: Final sudoers file check and if check is ok, make it live
        shell: visudo -q -c -f /usr/local/etc/sudoers.tmp && cp -f /usr/local/etc/sudoers.tmp /usr/local/etc/sudoers
    
        # might change this to fully manage the file in the future
      - name: update sshd_config
        lineinfile: dest=/etc/ssh/sshd_config state=present line='PasswordAuthentication no'
        lineinfile: dest=/etc/ssh/sshd_config state=present line='ChallengeResponseAuthentication no'
    
      - name: restart sshd
        service: name=sshd state=restarted enabled=yes
    
      - name: update /usr/local/etc/pam.d/sudo
        lineinfile: dest=/usr/local/etc/pam.d/sudo state=present line='{{item}}'
        with_items:
           - 'auth sufficient /usr/local/lib/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys'
           - 'auth required pam_deny.so'
           - 'account include system'
           - 'session required pam_permit.so'

Leave a Comment

Scroll to Top