When configuring a new server with Ansible, I wanted to create a new user, then switch to that new user for the remainder of the playbook. As with any Ansible playbook, it should be idempotent. The way to do accomplish this was not straightforward, due to the way the Ansible SSH user behaves.
The playbook layout
There are two roles: maybecreateuser and createuser.
The maybecreateuser role wraps the createuser with logic to test if the user exists and to handle the variable setup required to swap ansible_user. The createuser role contains the user creation tasks.
Testing if the user exists
Key points:
- Stash the
ansible_userinto another variable, before swapping in the value ofinitial_user.initial_useris a variable defined by this role and should be the name of the initial root user on the server. - Test if the user already exists by trying to SSH explicitly
Creating the user
- Create a user with no password set, to avoid dealing with password handling
- Copy the
~/.ssh/authorized_keysfile frominitial_user, in order to SSH in as this new user. This assumes yourinitial_userhas anauthorized_keysfile already (this is true on DigitalOcean if you provide your pubkey before creating the server). - Give the user sudo rights without a password
None of these are hard requirements. You may want your user to have a password and not give it nopasswd sudo. You may want to use a different SSH key.
Using it in a playbook
When using the maybecreateuser role, gather_facts: no must be set in the playbook. Otherwise, ansible will try to do gather_facts which requires an SSH connection, but the ansible_user might not exist yet.
Configuring inventory
Pass the initial_user if necessary to configure hosts whose initial user is not root.
Set the ansible_user to whatever you want, or don’t set it.