Ansible Sudoers Module
For example, I can take an empty Ubuntu machine, add an entry to my Ansible inventory with the appropriate roles, then run the Ansible playbook against it to set it up as described in the Ansible code.
It certainly beats logging in to the machine, installing packages, and editing config files by hand!
The Sudoers file describes what is permissible to run with sudo for a particular user or group.
To run a command as the super user, a user may run
sudo my-command (sudo being short for "super user do").
For example, this line allows any member of the sudo group to execute any command (requiring the user's password to do so):sudoers
%sudo ALL=(ALL:ALL) ALL
To simplify use, the requirement of the user's password can be dropped (essential for unattended use) for an
user with this line:
alice ALL=(ALL:ALL) NOPASSWD:ALL
Sudo use with specific commands may also be granted - this is the case I wrote the Sudoers Ansible module for.
On Ubuntu systems (at least) instead of writing all configuration to a single Sudoers file, any file in the
/etc/sudoers.d/ directory is read for configuration.
This is very helpful as it means that syntax errors in one of these files does not break sudo!
Generally when I want to allow a user to sudo a command, I wrap the functionality into it's own script and allow the
user sudo access for that specific script alone.
If a user needs to be able to restart a service, instead of allowing the user to sudo
/bin/systemctl restart myservice, I'll write that to
/usr/local/bin/restart-myservice and allow the user to sudo
This way, I don't need to worry about what options (and what order) may be used when writing the Sudoers rule.
I use Sensu to orchestrate checks and metric gathering across my infrastructure, and have
implemented several checks to check for available updates for installed packages.
For example, checking for available Nextcloud updates is done by executing
and processing the output.
The sensu user should not have access to the Nextcloud files and executables, and I wouldn't want to run the Nextcloud
executables as root as that'd allow a privilege escalation for the nextcloud user.
The check script (written to
/usr/local/bin/check-nextcloud-version.sh) is as follows:
#!/bin/bash output=$(sudo -u www-data php /var/www/html/nextcloud/occ update:check) echo "$output" echo "$output" | grep -qE 'updates? available' if [ $? -eq 1 ]; then exit 0 fi exit 1
The script uses sudo to run
occ update:check as the
It then prints the output (mostly for debug purposes) and checks to see whether "update available" or
"updates available" exists in the output of that command.
If updates are available, the check script returns 1 which indicates a warning level event to Sensu.
If the script did not print the output of the command, the update check command could be completely encapsulated within
To allow this script to be executed by the monitoring group, the following should be written to a file in the
%monitoring ALL=NOPASSWD: /usr/local/bin/check-nextcloud-version.sh
The Sudoers Module
While writing Ansible plays for my personal infrastructure, there were several cases where I wanted to manage sudo access via the Sudoers feature my Ubuntu machines. The most common use case for needing sudo access is to allow a monitoring agent to run some privileged command to check or measure something that required elevated privileges to read.
The main reason I wrote this Sudoers Ansible module was due to the number of times I needed to look up the format for the Sudoers file each time I needed to use it (or at least copy it from a previous use).
Before I wrote the Sudoers module, I would use Ansible's copy module to write the file:YAML
- name: allow monitoring to sudo the check copy: dest: "/etc/sudoers.d/monitoring-check-nextcloud-version" content: "%monitoring ALL=NOPASSWD:/usr/local/bin/check-nextcloud-version.sh\n"
The new line character at the end is critical - it does not work without it.
Using the module, the same functionality is achievable with this Ansbile:YAML
- name: allow monitoring to sudo the check sudoers: name: monitoring-check-nextcloud-version # The name of the file in the sudoers.d directory group: monitoring # the user or group may be specified for this rule command: /usr/local/bin/check-nextcloud-version.sh # a command or list of commands that are being granted by this rule nopassword: true # whether a password is required when using sudo for this rule state: present # whether this rule is to be kept or removed
My common defaults are set so you wouldn't normally set more than the name, group (or user), and command.
The Sudoers module supports several of the use cases that I've used for the Sudoers file - mostly allowing access to commands to specific users and groups. It does not currently support the aliasing features as I've actually never used them. I'm reasonably happy it'd be straight forward to add to this module though.
The module supports check mode and returns whether the invocation of the module caused a change or not.
At iWeb, We have a very similar use-case when managing sudoers files, so I decided the best way to use it in both places was to publish it as an Ansible collection in Ansible Galaxy.
This turned out to be a reasonably straight forward thing to do, however I was initially confused as to how publish a
collection that only contained modules.
When this is written into an Ansible structure, it would be added to the
However for a collection, it should be placed in the
Secondly, I found the process to update the version frustrating as the
galaxy.yml config file needs to be updated with
the tagged version of the code.
I had to go back and create a new version with the correct version in the config file and re-update it.
I would have liked the version to be populated or templated from the git tag if possible.
The collection must be built and uploaded to Ansible galaxy, I'm sure I could have written a CI job to do this, but it didn't seem worth it for the low frequency that I update the module.
This repository earned me my first two stars on GitHub, and apparently is being stored in their Arctic Archive Program.
Hopefully this module will be useful for others too.