Nick George
all/

Bootstrapping Ansible on FreeBSD

First published: April 2, 2024
Last updated: April 3, 2024

Automating tasks with Ansible has been a great way to learn about server management best practices and get Linux servers up and running quickly. When I started experimenting with FreeBSD1 in my homelab I was surprised that Ansible wasn’t well supported.

Python and sudo

The primary difficulty is that while Ansible is “agentless”, it does require Python on the target server. FreeBSD doesn’t clutter up your system with interpreters you may not need2, so using Ansible won’t work out of the box. After some fiddling, here is my basic ‘bootstrap’ playbook for FreeBSD. Note that FreeBSD also does not have sudo by default, so I also install that and initially use su to root for privilege escalation3 when bootstrapping.

---
- hosts: all
  gather_facts: false
  become: yes
  become_user: root
  become_method: su
  vars:
    - ansible_python_interpreter: "/usr/local/bin/python3.9"
    - user: "ansible"
    - user_pw: "{{ lookup('vars', 'user') | password_hash('sha512', 'thesecretsalt') }}"
  tasks:

  - name: bootstrap python
    ansible.builtin.raw: sh -c "pkg install -y python39"

  - name: install sudo
    ansible.builtin.shell: pkg install -y sudo

  - name: install bash
    ansible.builtin.shell: pkg install -y bash

  - name: Link python for later ansible discoverability
    ansible.builtin.file:
      src: "{{ ansible_python_interpreter }}"
      dest: "/usr/bin/python"
      state: link

This playbook assumes you can ssh to the default freebsd user. Linking my installed python to an Ansible/Linux friendly location will hopefully avoid future headaches. I also added a few more plays, creating a new user and adding them to the wheel group to continue configuration with a specifically created ansible user4 and adding SSH keys:


  - name: make wheel
    ansible.builtin.group:
      name: wheel
      state: present

  - name: ansible user
    ansible.builtin.user:
      name: "{{ user }}" 
      password: "{{ user_pw }}"
      shell: /usr/local/bin/bash
      state: present
      groups: wheel
      append: yes

  - name: sudo for ansible user
    ansible.builtin.lineinfile:
      path: /usr/local/etc/sudoers
      state: present
      regexp: '^%wheel ALL=(ALL:ALL) ALL'
      line: "%wheel ALL=(ALL:ALL) ALL"

  - name: make ssh dir for ansible
    ansible.builtin.file:
      path: /home/{{ user }}/.ssh
      mode: '0700'
      owner: "{{ user }}"
      state: directory

  - name: add ansible key
    ansible.builtin.lineinfile:
      path: "/home/{{ user }}/.ssh/authorized_keys"
      state: present
      line: "{{ lookup('file', '~/.ssh/local_bsd.pub') }}"
      create: true
      owner: "{{ user }}"
      state: present
      mode: '0600'

After this playbook, you should be able to run others normally using the newly created ansible user’s SSH key and become password.

Of course, change the password section, that is just an example.

I am hoping that after this bootstrap step I will have an easier time managing my FreeBSD servers and experimenting/configuring BSD jails.


  1. I’m using FreeBSD 14.0-RELEASE ↩︎

  2. I appreciate this. I don’t want things I won’t use and why assume I need Python, or Ruby, or NodeJS? ↩︎

  3. For more on Ansible Privilege escalation, see the docs: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html ↩︎

  4. Here I am using the username as the password as an example. Don’t actually do this. ↩︎