Systemd exact commands for sudoers file

Hello everyone,

I’m currently trying to update a couple of configuration scripts of a server.
The steps I want to do:

  1. Stop service
  2. Copy new configuration files for this service
  3. Start service

I have a sudoers file that allows the remote user to run systemctl start/stop/show/status for this specific service.
The sudoers file:

%REDACTED ALL= NOPASSWD: /bin/systemctl start REDACTED
%REDACTED ALL= NOPASSWD: /bin/systemctl stop REDACTED
%REDACTED ALL= NOPASSWD: /bin/systemctl restart REDACTED
%REDACTED ALL= NOPASSWD: /bin/systemctl status REDACTED
%REDACTED ALL= NOPASSWD: /bin/systemctl show

The problem is now that the commands in the sudoers file most likely not fit the commands ansible is using.
The task I want to run is:

    - name: "Stop service {{ service_name }}"
      ansible.builtin.systemd_service:
        name: "{{ service_name }}"
        state: stopped
      become: true

It fails with “password required”. The question is now, is there a way to edit the sudoers file to have ansible working without giving NOPASSWD Permissions on every command for the remote user?
Using ansible.builtin.command it works

You may also need:

%REDACTED ALL= NOPASSWD: /bin/systemctl show 'REDACTED'
%REDACTED ALL= NOPASSWD: /bin/systemctl list-unit-files *
%REDACTED ALL= NOPASSWD: /bin/systemctl is-active 'REDACTED'

since the module first checks to see if the specified unit exists before attempting to make any required changes. Note also the ' characters, as sudo rules without any wildcards must be exact matches, and the module is single quoting the given unit name. I did use a wildcard for list-unit-files, but that’s because I’m not sure how to easily interpret the following '{unit_search}*', since it’s a manipulation of the original unit name. The single-quotes around the unit name are also used by the module for all of the start/stop/restart/reload actions.

Additionally, I’m not familiar enough with sudo rules to know if it cares about symlink paths. Usually, /bin and /usr/bin are symlinked, and Ansible isn’t using an explicit path to systemctl, so Ansible might be trying to use /usr/bin/systemctl while all of your rules are for /bin/systemctl. This might be an important distinction for the sudo rules.

Edit: for reference: ansible/lib/ansible/modules/systemd_service.py at devel · ansible/ansible (github.com)

Unfortunately it seems to just not work. The become does not prepend the sudo to each command but to the whole python command which is used for the subcommand e.g.:

sudo -H -S -n  -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-htbihlgskndrxzpaectqhiopugwdsxww ; /usr/bin/python3 /home/USER/.ansible/tmp/ansible-tmp-1725957415.6666732-2937536-137956451165161/AnsiballZ_systemd_service.py'"'"'"'"'"'"'"'"' && sleep 0

Assuming modules will just use a specific command is not really possible, hence why:

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html#privilege-escalation-must-be-general

1 Like