Bootstrap FreeKB - Ansible - Understanding Become Privilege Escalation
Ansible - Understanding Become Privilege Escalation

Updated:   |  Ansible articles

Let's say you have a playbook that contains a command that requires some sort of elevated privilege, such as reboot.

---
- hosts: all
  tasks:
  - name: reboot OS
    ansible.builtin.reboot:
      msg: "Reboot initiated by Ansible"
      connect_timeout: 5
      reboot_timeout: 600
      pre_reboot_delay: 0
      post_reboot_delay: 30
      test_command: whoami
...

 

And john.doe does not have permission to issue the reboot command on the target server. 

[john.doe@server1 ~]# reboot
reboot: Permission denied

 

When running the playbook as john.doe, "permission denied" will be returned.

[Errno 13] Permission denied

 

There are a couple way to handle this.

  1. Run the playbook as a user that has permission to run the task that is causing permission denied to be returned
  2. Use "become" to become a user that has permission to run the task that is causing permission denied to be returned

Let's say john.doe is a member of the wheel group on the target server.

[john.doe@server1 ~]# groups
john.doe wheel

 

And members of the wheel group have been granted sudo NOPASSWD to ALL commands on the target server.

]# cat /etc/sudoers.d/wheel
%wheel ALL = (ALL) NOPASSWD: ALL

 

In this scenario, instead of using the reboot module, you could use the shell module with sudo and the task should run properly. In this example, the target system should be rebooted.

---
- hosts: all
  tasks:
  - ansible.builtin.shell: sudo reboot
...

 

But this approach is discouraged and should return WARNINGS. Instead, using "become" is the recommended approach.

[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo

 

In this scenario, if we are running the playbook as john.doe, adding the become: yes and become_method: sudo options to the task in the playbook that are only permitted with sudo should resolve permission denied and WARNINGS. In other words, the target server should be rebooted.

---
- hosts: all
  tasks:
  - name: reboot OS
    become: yes
    become_method: sudo
    ansible.builtin.reboot:
      msg: "Reboot initiated by Ansible"
      connect_timeout: 5
      reboot_timeout: 600
      pre_reboot_delay: 0
      post_reboot_delay: 30
      test_command: whoami
...

 

Or you can set become: yes and become_method: sudo at the play level (before pre_tasks / tasks / post_tasks) so that all tasks in the playbook are run with become sudo. In this example, if john.doe has been granted sudo permission to run both the reboot command and the /root/example.sh script then it may make sense to set become at the play level.

---
- hosts: all
  become: yes
  become_method: sudo
  tasks:
  - name: reboot OS
    ansible.builtin.reboot:
      msg: "Reboot initiated by Ansible"
      connect_timeout: 5
      reboot_timeout: 600
      pre_reboot_delay: 0
      post_reboot_delay: 30
      test_command: whoami
      
  - name: run /root/example.sh
    ansible.builtin.shell: /root/example.sh
...

 

Or you can set become: yes and become_method: sudo in a block so that all of the tasks in the block are run with the become permissions. In this example, the task that creates the /tmp/example.log file is not run with become sudo permissions, but the tasks in the block are run with become sudo permissions.

---
- hosts: all
  tasks:
  - name: create the /tmp/example.log file
    ansible.builtin.file:
      path: /tmp/example.log
      state: touch
  
  - block:
    - name: reboot OS
      ansible.builtin.reboot:
        msg: "Reboot initiated by Ansible"
        connect_timeout: 5
        reboot_timeout: 600
        pre_reboot_delay: 0
        post_reboot_delay: 30
        test_command: whoami
      
    - name: run /root/example.sh
      ansible.builtin.shell: /root/example.sh
      
    become: yes
    become_method: sudo
...

 

It is also noteworthy that on a systemd system, the systemctl command is used to reboot the system, and only root has permission to execute the systemctl command.

[john.doe@server1 ~]# ls -l /bin/systemctl
-rwxr-xr-x. 1 root root 717568 Feb  4 10:30 /bin/systemctl

 

Let's say john.doe uses sudo to invoke the reboot command.

[john.doe@server1 ~]# sudo reboot

 

If john.doe has not been added to the /etc/sudoers file, the following will be displayed.

john.doe is not in the sudoers file. This incident will be reported.

 

If john.doe has been added to the /etc/sudoers file, but has not been granted permission to the command being issued, the following will be displayed.

john.doe is not allowed to run sudo on server1.  This incident will be reported.

 

John Doe can be granted permission to the reboot command (or any other command).

 

If John Doe is granted sudo permission with password, John will be prompted to provide his password, like this.

[john.doe@server1 ~]# sudo reboot
Password for john.doe: ******

 

If John Doe is granted sudo permission with the NOPASSWD option, John will not be prompted to provide his password and the system will reboot.

[john.doe@server1 ~]# sudo reboot

 

Let's say john.doe attempts to reboot server1 using the shell module and sudo.

---
- hosts: all
  tasks:
    - name: "reboot using sudo"
      shell: "sudo reboot"

 

Assuming the following option is commented out in ansible.cfg or set to true . . .

# command_warnings = False

 

. . . and you are not using the warn parameter, like this . . .

- name: "reboot using sudo"
  shell: "sudo reboot"
  warn: "false"

 

Invoking the play should return the following warning. 

[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo

 

As the warning suggests, "become" should be used. There are different ways to use "become":




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 639011 in the box below so that we can be sure you are a human.