Using Ansible

Halo

Sorry to be quiet for a long time. I have moved to a new place and things are totally different, from a Windows guy now I am, yes, I really am a Linux guy. Please bear that no more PowerShell tips from now (until further changes).


Use Case:

I have been used Ansible for a while as a consumer that only wrote some simple playbook with Windows modules but I have no idea about Ansible in detail. Now, here is the thread from installation to some simple tasks


Solution:

Nothing much about the general idea, just set up the Ansible server (control machine) and how to connect to the Ansible client (remote machine), Inventory, Variables, Playbook and Vault. Maybe more ... later.
This guide will base on Ubuntu 16.04 xenial


Set Up

Make sure both control and remote have Python 2.7, Ansible uses Python to connect to the remote machine and this is an agentless tool so you only have to install the software on the control machine via this guide.


sudo apt-get update
sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

If you want to use Ansible on your private environment, you can use based on the virtualenv application on Python via this guide.

To test the setup, you can use


ansible all -m ping --ask-pass # default inventory
ansible -i customhosts remote -m ping --ask-pass # custom inventory

With the customhosts content as below


[local]
127.0.0.1
[remote]
192.168.14.1

--ask-pass option will prompt for the credential to access to the remote


Configure

As mentioned in the document, the default connection is SSH, so we will create a system user on both control and remote machine. Make sure this user is a sudoer. For ex, create an ansible user


sudo adduser ansible
sudo adduser ansible sudo

Note: use adduser instead of useradd based on this note.

The remote machine will play as an ssh server to let the control machine connect to it, so you will need to install openssh server on remote machine


sudo apt-get install openssh-server
sudo server ssh status # check the ssh service to verify the ssh server installed

To configure passwordless access to remote, you will need to follow this guide.
  • Create ssh key on control machine: ssh-keygen -t rsa 
  • Copy the public key to remote machine: ssh-copy-id ansible@<remoteIP>
  • On remote machine, in file /etc/ssh/sshd_config update the PermitRootLogin from prohibit-password to without-password. Then restart ssh service.
I have done a tweak to copy the whole .ssh directory of control machine to remote machine (make sure create same user name and password on both machines) so you don't have to do step 2 and 3.

To make the passwordless sudo then you can use following trick, but be CAREFUL, if you mess up with sudoers file, you will be in a bad time, I found people can restore the sudoers file by using pkexec to re-install sudo but I haven't been successful with it.
  • On remote machine, edit /etc/sudoers file by: sudo visudo -f /etc/sudoers
  • Add this line AT THE END of the file: ansible ALL=(ALL) NOPASSWD:ALL
Another way to use passwordless sudo (instead of using --ask-sudo-pass with ansible command) is to store the ansible_become_pass with ansible-vault (refer to vault session below). I prefer this way because you don't have to mess with the system configuration change on remote.



Usage

As I have just used Ansible for few months, so my knowledge is very limited. First of all, refer to this Best Practices page to make sure you can adapt the layout of the storage and  data structure of your ansible workspace.

For my case, I need to do the setup for platform type so I put all the remote hosts into a host inventory, each platform will have a playbook file and a variables file (under group_vars) for the list of applications to be installed.

ansible
    |_ servers                            # host file
    |_ os1.yml                           # playbook for os1
    |_ os2.yml                           # playbook for os2
    |_ group_vars
                |_ os1                     # apt list to install on os1
                |_ os2                     # apt list to install on os2
    |_ credentials.yml               # vault encrypted credentials
    |_ .vault_pass                     # private pass for AES256 vault encryption
    |_ sources                          # custom sources that for installation


Below are some tips and modules that I have experience with
  • apt_key: add apt key to repository
  • apt_repository: add a new source file under /etc/apt/sources.list.d. If you want to add a new repository to the current sources.list file, instead of using this module or use a raw command to append a line into sources.list, use lineinfile task
  • apt: you can install deb package by using deb option
  • with_dict: this option will use a json dictionary
  • become: a boolean flag will elevate the attached task to other elevated user in become_user, if no specification of become_user, root will be the elevated user
  • when: this is a powerful conditional and testing phase for your task. A note, each hyphen line is an AND condition
  • register: define a variable name. You might use some properties of this object such as stdout, stdoutlines, rc ... You can echo the whole object by using debug: var=[varname]
  • ignore_errors: skip error to keep going on in case you want to test something that might raise an error
  • systemd: some services might move under systemctl in later OS, this will be used instead of service task
  • pip: if there is multiple pip in your software collection (RHEL) then you have to point to a specific application instance which you want to use by executable option. For ex, I want to use rh-python36 pip then the executable will be executable="/usr/bin/scl enable rh-python36 -- pip"

Use ansbile vault to store your sensitive data, there are a lot of guidelines out there so I just want to keep a very short version here. For ex, I want to keep my sudo password when I want to use become option.
  • Create a yml file with the raw content, secrets.yml : ansible_become_pass: mysudopass
  • Use ansible vault to encrypt this file: ansible-vault encrypt secrets.yml  
  • This command will prompt you to enter and confirm the vault password (for ex, you will use vault password as 'myvaultpass')
  • Create a vault password file, .vault_pass (start with . to avoid ls by default),  to store a content: myvaultpass.
  • Then when you call the ansible command: ansible-playbook testplaybook.yml -i hosts --vault-password-file=.vault_pass
  • In your playbook you will use the ansible_become_pass by using
vars_files:
  - secrets.yml

Note: I read somewhere that use include_vars: secrets.yml however, from ansible 2.5, the console will echo the raw data to display so using vars_files is a fix for that issue

I use this setting from Jenkins, so I will store my playbook, vars file, secrets file into Git but I keep the .vault_pass in the ansible server. So another layer to protect from others if they can access only one area, they can only have secrets file but not vault pass key and vs they have vault pass key on ansible server but no secrets file, like the way to separate the public and private key.

That's for now with my 2 months studying :D

See you in the next article!

Comments

Post a Comment