Simple Ansible Paybook Without Python Installed In Target Machines

In my previous post related to Setting up and executing basic Ansible playbook, we have seen what Ansible is, learned how to setup Ansible and saw how to write a basic playbook and execute it.

In this post we will be looking into how to build our playbook when there is no python installed on the target machines. By default Ansible modules require python to be present in the target machines, since they are all written in python.

So first of all let's understand why this may be required and then we will proceed to the different ways to achieve that. There are mainly two case where this might be required:

  • The first case is installing python-simplejson on older (Python 2.4 and before) hosts that need it as a dependency to run modules, since nearly all core modules require it.
  • Another is speaking to any devices such as routers that do not have any Python installed. In any other case, using the shell or command module is much more appropriate.

So how do we achieve this in Ansible?

By using the raw module. It executes a low-down and dirty SSH command. To know more about the raw module in Ansible please visit here.

Note

If using raw from a playbook, you may need to disable fact gathering using gather_facts: no if you’re using raw to bootstrap python onto the machine.

  • If you want to execute a command securely and predictably, it may be better to use the command or shell modules instead.
  • the environment keyword does not work with raw normally, it requires a shell which means it only works if executable is set or using the module with privilege escalation (become).

Now let's write the same playbook as we did in the previous post in step-4 for creating a new user in the remote machine and enable ssh connection for the new user using the raw module. We are not going to use the raw module to simply bootstrap Python dependencies, rather we will see how to write the playbook so that it doesn't depend on python in the remote machines. So let's check out the playbook.

Note

For the below Ansible playbook I have assumed that we have a ansible_user and ansible_ssh_pass to run the playbook to the remote machines. Sample host file will be as follows,

192.0.2.50(your remote machine IP address or host name) ansible_user=<someuser> ansible_ssh_pass=<your_password>

Playbook1

 
  1. ---  
  2.   
  3. - hosts: all  
  4.   
  5. gather_facts: False  
  6.   
  7. become: True  
  8. vars:  
  9.   
  10. user: user1  
  11.   
  12. passw: Password1$  
  13. tasks:  
  14. - name: Check if user exists  
  15.   
  16. register: user1_exists  
  17.   
  18. raw: getent passwd {{user}}  
  19.   
  20. ignore_errors: true  
  21. - name: delete user1 user  
  22.   
  23. raw: userdel {{user}} -r  
  24.   
  25. when: user1_exists|success  
  26. - name: add user user1   
  27.   
  28. raw: useradd -m {{user}}  
  29. - name: add user password  
  30.   
  31. raw: usermod --password $(echo {{passw}} | openssl passwd -1 -stdin) {{user}}  
  32.   
  33. - name: make dir .ssh in crvp home  
  34.   
  35. raw: mkdir ../{{user}}/.ssh  
  36. - name: change ownership to crvp user  
  37.   
  38. raw: chown {{user}}:{{user}} ../{{user}}/.ssh  
  39. - name: give required permission to .ssh  
  40.   
  41. raw: chmod 777 ../{{user}}/.ssh/  
  42. - name: create authorized_keys   
  43.   
  44. raw: touch ../{{user}}/.ssh/authorized_keys  
  45. - name: change ownership to crvp user  
  46.   
  47. raw: chown {{user}}:{{user}} ../{{user}}/.ssh/authorized_keys  
  48. - name: give required permission to authorized_keys  
  49.   
  50. raw: chmod 666 ../{{user}}/.ssh/authorized_keys  
 

The above playbook is pretty self explanatory. The first thing to notice is the gather_facts which is set to false, since we are using ansible raw module.

In the variable section we have declared the user name and the password for the user which we are going to create in our remote machines.

In the task list, the 1st and the 2nd task is using a conditional and Jinja2 expressions. We have used condition and ignore_errors in the 1st task to make sure it gets executed even if there is an error response and the 2nd task will get executed depending on the response we get from task 1.To more about conditionals in Ansible please check here.

In the next script I have finally copied the ssh key from our Ansible host machine into authorized_keys in the remote machine, so that we can SSH into those remote machines using the new user and the new key.

Note

At the time when I was wrote these scripts, the become_user was not working due to a bug. Thus I had to break my script into two scripts and do the file copy operation in the 2nd scripts as the newly created user. Maybe it's fixed now; I will check once and update.

Playbook2

 
  1. — -  
  2.   
  3. - hosts: all  
  4. gather_facts: False  
  5. vars:  
  6.   
  7. user: user1  
  8.   
  9. passw: Password1$  
  10. tasks:  
  11. - name: local scp — copy key file into authorized_keys   
  12.   
  13. local_action: “command scp ../.ssh/user1_user.pub {{ansible_user}}@{{inventory_hostname}}:../{{user}}/.ssh/authorized_keys”  
  14. - name: give required permission to .ssh for user  
  15.   
  16. raw: chmod 0700 ../{{user}}/.ssh/  
  17.   
  18. become: true  
  19. - name: give required permission to authorized_keys for user  
  20.   
  21. raw: chmod 0600 ../{{user}}/.ssh/authorized_keys  
  22.   
  23. become: true  
 

In this playbook as we mentioned we are copying the public key for ssh into the authorized_keys of the newly created user. For file copy I have used local_action module, which helps us to run any command in the ansible host itself rather than in the remote machines. Inside the local_action we have used scp command which is used to copy file over SSH so here it copies the ../.ssh/user1_user.pub file to ../user1/.ssh/authorized_keys.

To know more about local_action check here.

So after running these two scripts in any number of remote machines (mentioned in the host file), we should be able to ssh onto those remote machines with the new user that we have created.

Hope this post will be helpful for those who want to write playbook without python dependency in the remote machines.