Embracing the Messiness in Search of Epic Solutions

Ansible: Handling Sudo Password with Homebrew

Posted

in

Table of Contents

Problem

When using the Ansible playbook to run Homebrew-related modules, it will prompt for a sudo password where necessary on specific tasks. For example, using the community.general.homebrew_cask module to (un)install the apps under /Applications directory will prompt for a sudo password on each app.

It is not possible to preemptively prompt for a sudo password before running the Ansible playbook:

# Does not work!
sudo -v

ansible-playbook main.yml

It is also not possible to perform clever tricks like this to extend the sudo timeout:

# Does not work, too!
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &

ansible-playbook main.yml

Root Cause

This is not an Ansible problem. This behavior exists because Homebrew always clears the sudo password cache to prevent privilege escalation attacks [link 1] [link 2].

The upside is the community.general.homebrew_cask module provides a variable for passing in a sudo password, for example:

- name: Install/Upgrade cask packages
  community.general.homebrew_cask:
    name: '{{ item }}'
    state: upgraded
    greedy: true
    install_options: force,no-quarantine
    sudo_password: "{{ ansible_become_pass }}"
  loop: '{{ homebrew_cask_packages_present }}'

Solution

While storing passwords in a file is not ideal, it prevents these Ansible tasks from prompting for a sudo password each time. The ansible-vault command can be used to store the password (and other secrets) securely.

First, create an encrypted file.

ansible-vault create vault.yml

You will be prompted for a new vault password. Once provided, enter the following into the file.

ansible_become_pass: [YOUR_SUDO_PASSWORD]

Now, your encrypted file should be created in the location you specified with the proper permission set:

$ ls -la
total 88
drwxr-xr-x@ 18 shitty.author  staff   576 Sep  4 09:06 .
drwxr-xr-x  12 shitty.author  staff   384 Jun 27 12:47 ..
-rw-r--r--   1 shitty.author  staff    99 Mar  1  2024 .ansible-lint
-rw-r--r--   1 shitty.author  staff   193 Mar 19 08:57 .editorconfig
drwxr-xr-x  16 shitty.author  staff   512 Sep  4 09:06 .git
-rw-r--r--   1 shitty.author  staff   243 Mar  1  2024 .gitignore
drwxr-xr-x   8 shitty.author  staff   256 Sep  4 09:35 .idea
drwxr-xr-x   6 shitty.author  staff   192 Mar  4  2024 .venv
-rw-r--r--   1 shitty.author  staff    72 Mar  1  2024 .yamllint
-rw-r--r--   1 shitty.author  staff  1079 Mar  1  2024 LICENSE.md
-rw-r--r--@  1 shitty.author  staff  1796 Sep  4 08:39 README.md
-rw-r--r--   1 shitty.author  staff   381 Mar  1  2024 ansible.cfg
-rw-r--r--   1 shitty.author  staff    65 Mar  1  2024 inventory.yml
-rw-r--r--@  1 shitty.author  staff  1450 Sep  4 09:06 main.yml
drwxr-xr-x  16 shitty.author  staff   512 Aug 12 09:32 roles
-rw-------@  1 shitty.author  staff   484 Sep  4 09:01 vault.yml

If you open vault.yml, the content should look gibberish.

$ cat vault.yml                                                                                  ✔
$ANSIBLE_VAULT;1.1;AES256
62343635616463643935613965336336323366653565646137616238663266633936363463611364
6139353639666163323066653733663763323236663361380a646264623465616461646637315661
34396438316137383130366330313431653336396435656562356430333762373866663234383230
6265656164346531660a626431383230326664393839316131626330353562363164313439661863
31343363323236333531303139396662386531626165663732386233626538646338333133375936
6535626465393233386634393934623438393535626365313132

In the Ansible playbook, specify vault.yml under vars_files.

---
- name: My Playbook
  hosts: all
  vars_files:
    - vault.yml
  roles:
    - ...

Finally, run the Ansible playbook with the –ask-vault-pass option, where you will be prompted for the vault password once before Ansible executes the playbook.

ansible-playbook main.yml --ask-vault-pass

Now, you will not be prompted for a sudo password every time Homebrew-related tasks run.

Comments

Leave a Reply