0

I want to have a user that is only able to start/stop/restart/status a service via an Ansible playbook.

The playbook looks like this:

host: my-server
remote_user: my-user
tasks:
  - name: "Start my-service"
    service:
      name: my-service
      state: started
      daemon_reload: yes
    become: true

I've tried using the sudoers file to restrict the privileges of my-admin but this does not works as the command Ansible is runnning is (simplified):

sudo /bin/sh -c "python /tmp/ansible-xxxxxx.py"

Obviously, I can't allow my-admin to run /bin/sh as root as this would allow everything to be run as root. What configuration should I ? What should I change ?

MoaMoaK
  • 33
  • 8
  • Does this answer your question? [systemd: Grant an unprivileged user permission to alter one specific service](https://serverfault.com/questions/841099/systemd-grant-an-unprivileged-user-permission-to-alter-one-specific-service) – Michael Hampton Mar 01 '21 at 19:42
  • @MichaelHampton Kind of. I was hoping for a simpler solution than using policyKit rules. But I will give a try at user services. – MoaMoaK Mar 02 '21 at 09:55
  • 1
    The polkit approach is a very simple way to allow very fine grained access to a user without sudo, if it's available on your distro (i.e. not Debian-based, as they still haven't joined the rest of the planet in the 2010s in this respect). It's absolutely the first approach I'd recommend for just about any scenario where you have people who should only be able to perform a small subset of tasks related to the service. – Michael Hampton Mar 02 '21 at 18:51

2 Answers2

1

In general:

You can't. Ansible privilege escalation is all or nothing. See: https://docs.ansible.com/ansible/latest/user_guide/become.html#privilege-escalation-must-be-general

Limit with sudo

The classic approach: Your user is allowed to access that system and you create a sudo policy that severely restricts and limits what commands (and with which arguments) your user can run with sudo. That is possible, quite easy to maintain but comes with the sudo limitation that then those commands need to be used in the exact syntax of your policy.
That more or less prohibits using native Ansible modules and privilege escalation methods to perform the tasks.

You can still use a playbook, but then you will get something ugly like:

tasks:
  - name: "Start my-service with sudo"
    ansible.builtin.command: /usr/bin/sudo /usr/bin/systemctl start my-service.service

and even uglier kludges when your sudo policy still requires a password as well.

Use Ansible tower:

To avoid giving your user both access that system and setting up that restricted sudo policy:

  • You set up a service account for Ansible playbooks that has the required unlimited privilege escalation.
  • You set up Ansible Tower as the only system with the credentials to log in with the Ansible service account.
  • You use the user management and ACL's from Ansible Tower to designate which plays your user can run against which hosts. Your users plays will be executed using the Ansible service account, but you don't need to hand those over to your user.

https://docs.ansible.com/ansible-tower/latest/html/userguide/security.html

Bob
  • 5,335
  • 5
  • 24
  • I already thought of the sudo approach but as you said it's not very pretty and I prefer to avoid (but it's my backup solution, if I can't find anything else). And Ansible Tower might be a solution but not a short-term one as I currently do not use it – MoaMoaK Mar 02 '21 at 09:48
0

You could try something like this:

Add a file called youruser in /etc/sudoers.d/youruser with the content bellow:

youruser   ALL=(ALL)       NOPASSWD: /usr/bin/python /tmp/ansible-xxxxxx.py

Your user is able to execute the python command, with sudo rights against the /tmp/ansible-xxxxxx.py file

Of course, the user is basically able to run any python command with sudo rights.

As far as I know you cannot pass non-command arguments into sudo if that argument varies. If you need to pass a variable, I recommend a wrapper script that does that.

Bogdan Stoica
  • 363
  • 2
  • 8
  • Unfortunately, with Ansible, the "xxxxx" part is actually a (random) number (probably a timestamp and/or a hash), so I can't predict what it is. And also, the command run is `sudo /bin/sh -c "/usr/bin/python ..."` not directly `sudo /usr/bin/python` – MoaMoaK Mar 02 '21 at 09:36
  • And making the user able to run any python command is a no-go for me, as this is equivalent to having root access (you simply have execute a python script that start a subprocess with any command) – MoaMoaK Mar 02 '21 at 09:38
  • As I was saying then you should use a wrapper script that does whatever you need – Bogdan Stoica Mar 02 '21 at 12:00