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
.
I’m using
FreeBSD 14.0-RELEASE
↩︎I appreciate this. I don’t want things I won’t use and why assume I need Python, or Ruby, or NodeJS? ↩︎
For more on Ansible Privilege escalation, see the docs: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html ↩︎
Here I am using the username as the password as an example. Don’t actually do this. ↩︎