Is it possible to use become
in a handler?
We are running ansible 2.9.3 on a RHEL 7.4 machine. We have a user who is modifying some config files for a daemon (Consul), and we want the service to restart after any configuration change. We have a notify in the tasks, and a handler.
The files are getting modified properly, and the handler is getting notified and it runs. However, the sudo rule is not working correctly as Ansible exits with a failure:
"module_stderr": "sudo: a password is required\n"
When they run it from the command line, the user can run any systemctl commands they want using sudo commands; eg sudo systemctl restart consul
and sudo systemctl restart consul.service
work famously. Only the Ansible handler demands the password.
Here is our handler:
---
- name: Restart consul
service:
name: consul
state: restarted
become: yes
become_user: root
become_method: sudo
What is the magic inside the sudoers file that Ansible wants? I have looked for clues from the ansible -vvv
output but the only thing it tells me is as below. It looks like it wants to run something like
sudo -H -S -n -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-hltnfuwykrbhkmyixwzzockacxeosntn ; /usr/bin/python /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/AnsiballZ_systemd.py'"'"'
which would be impossible to put in our sudoers file. Here's the output from the handler:
RUNNING HANDLER [workdir : Restart consul] *****************************************************************************************************
task path: /home/consinstall/bitbucket/workdir/roles/deploy/handlers/main.yml:3
<testhost01> ESTABLISH LOCAL CONNECTION FOR USER: consinstall
<testhost01> EXEC /bin/sh -c 'echo ~consinstall && sleep 0'
<testhost01> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861 `" && echo ansible-tmp-1584133543.53-230020740311861="` echo /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861 `" ) && sleep 0'
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/systemd.py
<testhost01> PUT /home/consinstall/.ansible/tmp/ansible-local-79139pfL0dr/tmpauDoVw TO /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/AnsiballZ_systemd.py
<testhost01> EXEC /bin/sh -c 'chmod u+x /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/ /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/AnsiballZ_systemd.py && sleep 0'
<testhost01> EXEC /bin/sh -c 'sudo -H -S -n -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-hltnfuwykrbhkmyixwzzockacxeosntn ; /usr/bin/python /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/AnsiballZ_systemd.py'"'"' && sleep 0'
<testhost01> EXEC /bin/sh -c 'rm -f -r /home/consinstall/.ansible/tmp/ansible-tmp-1584133543.53-230020740311861/ > /dev/null 2>&1 && sleep 0'
fatal: [testhost01]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"daemon_reexec": false,
"daemon_reload": false,
"enabled": null,
"force": null,
"masked": null,
"name": "consul",
"no_block": false,
"scope": null,
"state": "restarted",
"user": null
}
},
"msg": "Unable to start service consul: Job for consul.service failed because the control process exited with error code. See \"systemctl status consul.service\" and \"journalctl -xe\" for details.\n"
}
META: ran handlers
NO MORE HOSTS LEFT *******************************************************************************************************************************************
PLAY RECAP ***************************************************************************************************************************************************
testhost01 : ok=2 changed=1 unreachable=0 failed=1 skipped=2 rescued=0 ignored=0
Ansible does not simply run
systemctl
. The service module determines the correct service manager for your system, then transfers an appropriate Python module with proper state reporting and error checking.The necessary sudo rule is running arbitrary python scripts as the become_user. It is near impossible to limit this, so Ansible users in less restrictive environments tend to give the Ansible user sudo to run all.
An alternative to remote Ansible ssh-ing in and becoming root is to run plays from an already privileged process. Think ansible-pull style clone and run from root's crontab. It is possible to become a less privileged user for tasks that don't require it.
raw module technically doesn't need to run any scripts, but that severely limits Ansible as you can't use modules.
Another write up of this: Can't use sudo command-limiting in Ansible.