Making Ansible, Doas and OpenBSD play nicely
Update 11 Jan 2020: The behaviour of doas changed in OpenBSD 6.6 so the environment specification described below is unnecessary. As of 6.6, doas sets HOME and USER to reflect the target user, like sudo. For details see openbsd-tech
A little while ago, OpenBSD replaced sudo in the base system with doas. This transition follows a typical path in the OpenBSD community where a large, difficult to audit daemon or key application is replaced by an auditable and securable alternate implementation. At the same time, features are pruned if they add significant complexity. I don’t need all the features of sudo and I like the simplicity and security of doas so I wanted to switch. I use Ansible to provision and manage my small collection of servers and when version 2.0 added support for privilege escalation via doas (via the become keyword) I started to make my switch. The main use-case in my Ansible playbooks is where I run as root and become
my non-admin user so that permissions are set correctly by default, and in this case doas behaves differently…
# /usr/bin/env | grep -E '^(HOME|USER)='
HOME=/root
USER=root
# sudo -u esteele /usr/bin/env | grep -E '^(HOME|USER)='
USER=esteele
HOME=/home/esteele
# doas -u esteele /usr/bin/env | grep -E '^(HOME|USER)='
HOME=/root
USER=root
The key difference is which environment variables are propagated from the original session. I find doas to be a little unintuitive in this respect, particularly the inability in the new session to write to the directory specified by $HOME
and this behaviour causes problems with the Ansible git and the pip tasks. The git task expects $USER
to correspond to the effective user id and the pip task expects $HOME
to be the home directory of the effective user id. The unexpected doas environment meant the tasks were trying to write files, as my non-admin user, under /root which was unsurprisingly unsuccessful. Fortunately Ansible has a way to specify environment variables for a task and even though it’d be preferable for the become
mechanism to take care of this, it’s an effective workaround (albeit a slightly dirty one).
The example below, from my web host playbook, ties the environment specification and the doas become in a block
# doas preserves USER and HOME, which is different to sudo, however by
# specifying them as environment variables we can proceed.
# USER is required for git, and HOME is required for pip
- block:
- name: Checkout wordspeak repo
git: repo=ssh://git@github.com/edwinsteele/wordspeak.org.git
dest=/home/esteele/Code/wordspeak.org
- name: Setup nikola virtualenv
pip: requirements=/home/esteele/Code/wordspeak.org/requirements.txt
virtualenv_command=/usr/local/bin/virtualenv
virtualenv=/home/esteele/.virtualenvs/wordspeak_n7
become: True
become_method: doas
become_user: esteele
environment:
USER: esteele
HOME: /home/esteele
And having tied this together, I can remove the sudo package!
- name: Remove sudo
openbsd_pkg: name=sudo-- state=absent