Making Ansible, Doas and OpenBSD play nicely

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)='
# sudo -u esteele /usr/bin/env | grep -E '^(HOME|USER)='
# doas -u esteele /usr/bin/env | grep -E '^(HOME|USER)=' 

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://                                                                                                          

  - name: Setup nikola virtualenv                                                                                                                                         
    pip: requirements=/home/esteele/Code/                                                                                                   

  become: True                                                                                                                                                            
  become_method: doas                                                                                                                                                     
  become_user: esteele                                                                                                                                                    
    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