How to Use Ansible

Ansible symbolAnsible is an easy to use automation software that can update a server, configure tasks, manage daily server functions and deploys jobs as needed on a schedule of your choosing. It is usually administered from a single location or control server and uses SSH to connect to the remote servers. Because it employs SSH to connect, it is very secure and, there is no software to install on the servers being managed. It can be run from your desktop, laptop or other platforms to assist with automating the tedious tasks which every server owner faces.

Once it is configured, Ansible performs tasks based on an ordered list of assignments in what is called a Playbook. The Playbook outlines what tasks need to be run on the remote server and in what order. Once this is configured, Ansible acts like a bash for-loop command that allows a section of code to be repeated over and over again. The difference between using a bash command and Ansible is that Ansible is idempotent. The term Idempotent sounds a little scary, but it merely means that you can make the same type of request over and over again and unless something has changed, you will get the same result.

Pre-flight: Server Requirements

Source Server Requirements

Ansible requires the installation of Python 2.7 or Python 3.5 on the source server. The source server is where you will be running the tasks in the playbook for the remote servers. The remote servers receive commands defined in the playbook.  A playbook is a file which defines the scripts that will be run on the remote servers.

Note:
Unfortunately, Windows is unsupported as a source server. Certain Ansible plugins and/or modules will have other needs or requirements. Usually, these plugins or modules are installed on the same server of the Ansible installation.

Let’s start by installing Python on the source server.
root@test:~# apt-get install python

 

Target Server Requirements

The only requirement from the target server is an open SSH port. Access can also be granted for scp (secure copy) and/or SFTP connections if configured in the /etc/ansible/ansible.cfg file.

Install Ansible On Ubuntu 16.04

To install Ansible on a source Ubuntu server, let’s follow these steps:

Note:
The PPA for Ansible is here: https://launchpad.net/~ansible/+archive/ubuntu/ansible if you would like to review the versions available for your variant of Ubuntu.

root@test:~# apt-get update
root@test:~# apt-get install software-properties-common
root@test:~# apt-add-repository ppa:ansible/ansible
root@test:~# apt-get update
root@test:~# apt-get install ansible
(install text)After this operation, 42.0 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Answer “Y” to the prompt. The install will complete and take you back to the command prompt. Now, let’s check the version of Ansible installed.

Check Ansible Version

root@test:~# ansible --version
ansible 2.7.0
 config file = /etc/ansible/ansible.cfg
 configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
 ansible python module location = /usr/lib/python2.7/dist-packages/ansible
 executable location = /usr/bin/ansible
 python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]

As an alternative, you can also install Ansible on your CentOS 7 server.
Ansible also can be installed on RedHat, Debian, MacOS, and any of the BSD flavors!

Install Ansible on CentOS 7

In order to install Ansible on a source CentOS 7 server, follow these steps.
First, we need to make sure that the CentOS 7 EPEL repository is added:

[root@test ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

[root@test ~]# yum install epel-release
Loaded plugins: fastestmirror, priorities, universal-hooks
Loading mirror speeds from cached hostfile

...
Resolving Dependencies
--> Running transaction check
---> Package epel-release.noarch 0:7-11 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
==========================================================================================================
Package Arch Version Repository Size
==========================================================================================================
Installing:
epel-release noarch 7-11 system-extras 15 k
Transaction Summary
==========================================================================================================
Install 1 Package
Total download size: 15 k
Installed size: 24 k
Is this ok [y/d/N]: y
Downloading packages:
epel-release-7-11.noarch.rpm | 15 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : epel-release-7-11.noarch 1/1
Verifying : epel-release-7-11.noarch 1/1
Installed:
epel-release.noarch 0:7-11
Complete!

Select “y”. The EPEL repo will then be added. Once the repository is enabled, we can install Ansible with yum:

root@test:~# yum install ansible
Loaded plugins: fastestmirror, priorities, universal-hooks
Loading mirror speeds from cached hostfile
epel/x86_64/metalink                                                               | 18 kB 00:00:00
* EA4: 208.100.0.204
* cpanel-addons-production-feed: 208.100.0.204
* epel: mirrors.liquidweb.com
epel                                                                               | 3.2 kB 00:00:00
(1/3): epel/x86_64/group_gz                                                        | 88 kB 00:00:00
(2/3): epel/x86_64/updateinfo
(3/3): epel/x86_64/primary                                                         | 3.6 MB 00:00:00
epel                                                                                          12756/12756
Resolving Dependencies
… (dependencies check)
Dependencies Resolved
==========================================================================================================
Package                        Arch Version            Repository Size
==========================================================================================================
Installing:
ansible                        noarch 2.4.2.0-2.el7            system-extras 7.6 M
Installing for dependencies:
21 k
Transaction Summary
==========================================================================================================
Install  1 Package (+17 Dependent packages)
Total download size: 12 M
Installed size: 58 M
Is this ok [y/d/N]:


Select “y” to start the Ansible install:

Is this ok [y/d/N]: y
… Downloading 18 packages:
----------------------------------------------------------------------------------------------------------
Total                                                                      30 MB/s | 12 MB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
… (installing 18 python related software)
...
Installed:
ansible.noarch 0:2.4.2.0-2.el7
Dependency Installed:
... (dependencies verified)
Complete!

Check Ansible Version on CentOS 7

Now, let’s verify the version installed:

root@test ~]# ansible --version
ansible 2.4.2.0
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Jul 13 2018, 13:06:57) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]

 

Setting Up Ansible Connections

Initially, we will be adding server names or IP’s to the /etc/ansible/hosts file to identify which “ungrouped” servers and “groups” of servers we are going to be connecting to. We mention ungrouped and grouped in this specific order because this is the way the Ansible hosts file is usually arranged.

We can use any name we like for the hosts file itself but typically it is just called hosts. Ansible also states that the hosts file can also be identified as an inventory file and, you can have multiple inventory files.

Let’s start by opening the hosts file with vim and inserting some entries into the file.

root@test:~vim /etc/ansible/hosts
Here is what the default hosts file will look like:

# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
# Example 1: Ungrouped hosts, specify before any group headers.
#green.example.com
#blue.example.com
#192.168.100.1
#192.168.100.10
# Example 2: A collection of hosts belonging to the 'webservers' group
#[webservers] #alpha.example.org
#beta.example.org
#192.168.1.100
#192.168.1.110
# If you have multiple hosts following a pattern you can specify
# them like this:
#www[001:006].example.com
# Example 3: A collection of database servers in the 'dbservers' group
#[dbservers] #
#db01.intranet.mydomain.net
#db02.intranet.mydomain.net
#10.25.1.56
#10.25.1.57
# Here's another example of host ranges, this time there are no
# leading 0s:
#db-[99:101]-node.example.com


As you can see, there are individual servers “#
green.example.com”, and groups like #[webservers] which have multiple servers under the group and, another section with multiple servers listed like #db-[99:101]-node.example.com which identifies all of the individual servers from 99-101; eg.

  • db-99-node.example.com
  • db-100-node.example.com
  • db-101-node.example.com

So, let’s quickly add another server to the #[webservers] group:

#[webserver1]
#alpha.example.org
#beta.example.org
#192.168.1.100
#192.168.1.110gamma.example.com

Now, simply save the file using :wq

Note:
Make sure you uncomment any ‘#’ entries you place in the file otherwise, the entry is excluded!

 

SSH Keys

You can set up public SSH keys from the control server to log in to those remote servers noted in the hosts file. In this case, you simply want to make sure your local SSH keys are located in the /root/.ssh/authorized_keys file on the remote systems. (Depending on your setup, you may wish to use Ansible’s –private-key option to specify a .pem file instead)

 

Verify Ansible Connections

The ansible inventory file (/etc/ansible/hosts) contains the server names you will have control over and can run tasks against. To verify Ansible’s connectivity, run:

ansible remote -m ping

 

Ansible Playbooks

Ansible playbooks (also called inventory files) define the tasks ran on the remote servers. You can have one playbook or multiple playbooks to accomplish different tasks on different servers.  To easily apply a task to all of the servers in a pool, use the ‘group’ name to apply the task for that group (using the example above, you would use the [webserver1] in the command.

 

Create a Playbook

Step 1: In order to create a playbook, let’s create a new file in the /etc/ansible/playbooks/ folder:

mkdir -p /etc/ansible/playbooks/ && touch /etc/ansible/playbooks/playbook.yml && vim /etc/ansible/playbooks/playbook.yml

 

Step 2: Let’s add a server and file entry into the playbook filer:

(Click the insert key to open VIM’s edit access on the file)

- hosts: gamma.example.com
 tasks:
     - name: Create file
       file:
           path: /tmp/test.txt
           state: touch


Once we have added the entry, let’s save the file using

:wq

Step 3: Now, to set up 0644 permissions on that file, we can reopen it and add another line defining the permission set:

- hosts: gamma.example.com
 tasks:
     - name: Create file
       file:
           path: /tmp/test.txt
           state: touch            mode: "u=rw,g=r,o=r"

Again, let’s save the file using

:wq

Step 4: Next, let’s create a folder and then place a text file in it using Ansible. We will add another section defining the element needed:

- hosts: gamma.example.com
 Tasks:       - name: Create folder
       path: /home/tmp/
           state: directory
           mode: 0755
     - name: Create file
       file:
           path: /home/tmp/test.txt
           state: touch            mode: "u=rw,g=r,o=r"

Once we have added this entry, save the file using

:wq

 

Running a Playbook

To start a playbook, simply run:

ansible-playbook /etc/ansible/playbooks/playbook.yml

or if you have multiple playbooks in a folder, can run a specific playbook using the -i <path> option from the command line:

ansible-playbook -i /etc/ansible/playbooks/playbook1.yml
In addition to .yaml files, Ansible can use .json files as well to control the playbook. It is also very easy to convert 
bash or shell scripts into playbooks as well!

Schedule a Playbook Using Cron

As an additional option, you can schedule a playbook to run at a specific time using your servers cron command! To accomplish this, log in to your server as root and run the following command:

crontab -e
This command opens a temporary cron file in your system’s 
default text editor and then simply add a line like so:

0 4 * * * /usr/bin/ansible-playbook /etc/ansible/playbooks/playbook.yml
this will run the
/etc/ansible/playbooks/playbook.yml file at 0400 a.m. using the ansible-playbook command.

 

Troubleshooting A Playbook

Sometimes, a set of commands in the playbook file may fail. If it does, you have several options to address this. Generally, playbooks will simply stop completing the commands in the playbook. If this occurs, you can define a follow-up task in the playbook to overlook the error by adding another section like so:

- name: ignore this error
 command: /bin/false
 ignore_errors: yes


Unreachable Hosts

this command will only work when the task is run but returns a “failed” value.

If Ansible fails to connect to a server, it will set the host as being ‘UNREACHABLE’. This effectively removes the server temporarily from the list of active hosts for that task. To correct this, we can use an entry to reactivate them and have all current hosts previously indicated as being unreachable cleared, so subsequent tasks can use the playbook again.

meta: clear_host_errors


Handlers and Failure

A handler is simply a specially named task that runs when told to by another task. Handlers are executed at the end of the playbook by default as opposed to other tasks, which are executed immediately when defined within the playbook. This behavior can be modified by using the

--force-handlerscommand-line option, or by including

force_handlers: Truein a playbook, or addingforce_handlers = Truein the ansible.cfg file.


If you want to force a handler to run in the middle of two separate tasks instead of at the end of the playbook, you will need to add this entry between the two tasks:

- meta: flush_handlers

When handlers are “forced” like this, they will run when notified even if a task fails on that host.

Note:
Certain errors can still prevent the handler from running, such as a host becoming unreachable.
Handlers will only be visible in the output if they have actually been executed. Also, handlers are only fired when there are changes made by a task. For example, a task may update a specific configuration file and then notify a handler to restart a service. If a task in the same playbook fails later on, the service will not be restarted despite the previous configuration change.

Overall, Ansible is an indispensable tool for managing and administrating a single server or an entire group of geographically diverse servers.

 

Getting Started with Ubuntu 16.04 LTS

A few configuration changes are needed as part of the basic setup with a new Ubuntu 16.04 LTS server. This article will provide a comprehensive list of those basic configurations and help to improve the security and usability of your server while creating a solid foundation to build on.

Root Login

First, we need to get logged into the server. To log in, you will need the Ubuntu server’s public IP address and the password for the “root” user account. If you are new to server administration, you may want to check out our SSH tutorial.
Start by logging in as the root user with the command below (be sure to enter your server’s public IP address):
ssh root@server_ipEnter the root password mentioned earlier and hit “Enter.” You may be prompted to change the root password upon first logging in.

 

Root User

The root user is the default administrative user within a Linux(Ubuntu) environment that has extensive privileges. Regular use of the root user account is discouraged as part of the power inherent within the root account is its ability to make very adverse changes. The control of this user can lead to many different issues, even if those changes made are by accident.
The solution is to set up an alternative user account with reduced privileges and make it a “superuser.”

 

Create a New User

Once you are logged in as root, we need to add a new user account to the server. Use the below example to create a new user on the server. Replace “test1” with a username that you like:

adduser test1

You will be asked a few questions, starting with the account password.
Be sure to enter a strong password and fill in any of the additional information. This information is optional, and you can just hit ENTER in any field you wish to skip.

 

Root Privileges

We should now have a new user account with regular account privileges. That said, there may be a time when we need to perform administrative level tasks.
Rather than continuously switching back and forth with the root account, we can set up what is called a “superuser” or root privileges for a regular account. Granting a regular user administrative rights will allow this user to run commands with administrative(root) privileges by putting the word “sudo” before each command.
To give these privileges to the new user, we need to add the new user to the sudo group. On Ubuntu 16.04, users that belong to the sudo group are allowed to use the sudo command by default.
While logged in as root, run the below command to add the newly created user to the sudo group:

usermod -aG sudo test1

That user can now run commands with superuser privileges using the sudo command!

 

Public Key Authentication

Next, we recommend that you set up public key authentication for the new user. Setting up a public key will configure the server to require a private SSH key when you try to log in, adding another layer of security to the server. To setup Public Key Authentication, please follow the steps outlined in our “Using-SSH-Keys” article.

 

Disable Password Authentication

Following the steps outlined in the previously mentioned “Using-SSH-Keys” article, results in the new user ability to use the SSH key to log in. Once you have confirmed the SSH Key is working, we can proceed with disabling password-only authentication to increase the server’s security even further. Doing so will restrict SSH access to your server to public key authentication only, reducing entry to your Ubuntu server via the keys installed on your computer.

Note
You should only disable password authentication if you successfully installed and tested the public key as recommended. Otherwise, you have the potential of being locked out of your server.

To disable password authentication on the server, start with the sshd configuration file. Log into the server as root and make a backup of the sshd_config file:

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

Now open the SSH daemon configuration using nano:

nano /etc/ssh/sshd_config

Find the line for “PasswordAuthentication” and delete the preceding “#” to uncomment the line. Change its value from “yes” to “no” so that it looks like this:

PasswordAuthentication no

The below settings are important for key-only authentication and set by default. Be sure to double check to configure as shown:

PubkeyAuthentication yes
ChallengeResponseAuthentication no

Once done, save and close the file with CTRL-X, then Y, then ENTER.

We need to reload/restart the SSH daemon to recognize the changes with the below command:

systemctl reload sshd

Password authentication is now disabled, and access restricted to SSH key authentication.

Set Up a Basic Firewall

The default firewall management on Ubuntu is iptables. Iptables offers powerful functionality. However, it has a complex syntax that can be confusing for a lot of users. A more user-friendly language can make managing your firewall much easier.
Enter Uncomplicated Firewall (UFW); the recommended alternative to iptables for managing firewall rules on Ubuntu 16.04. Most standard Ubuntu installations are built with UFW by default. A few simple commands can install where UFW is not present.

 

Install UFW

Before performing any new install, it is always best practice to run a package update; you’ll need root SSH access to the server. Updating helps to ensure that the latest version of the software package. Use the below commands to update the server packages and then we can proceed with the UFW install:

apt update

apt upgrade

With the packages updates, it’s time for us to install UFW:
apt install ufwOnce the above command completes, you can confirm the UFW install with a simple version command:
ufw --version

UFW is essentially a wrapper for iptables and netfilters, so there is no need to enable or restart the service with systemd. Though UFW is installed, it is not “ON” by default. The firewall still needs to be enabled with the below command:

ufw enable

Note
Recreating any pre-existing iptables rules is necessary for UFW. It is best to set up the basic firewall rules then enable UFW to ensure you are not accidentally locked out while working via SSH.

 

Using UFW

UFW is easy to learn! Various programs can provide support for UFW in the form of app profiles which are pretty straightforward. Using the app profiles, you can allow or deny access for specific applications. Below are a few examples of how to view and manage these profiles:

  • List all the profiles provided by currently installed packages:

ufw app list

Available applications:
Apache
Apache Full
Apache Secure
OpenSSH

  • Allow “full” access to Apache on port 80 and 443:

ufw allow "Apache Full"

Rule added
Rule added (v6)

  • Allow SSH access:

ufw allow "OpenSSH"

Rule added
Rule added (v6)

  • View the detailed status of UFW:

ufw status verbose

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action From
--                         ------ ----
22/tcp (OpenSSH)           ALLOW IN Anywhere           
22/tcp (OpenSSH (v6))      ALLOW IN Anywhere (v6)

As you can see, the App profiles feature in UFW makes it easy to manage services in your firewall. Newer servers will not have many profiles to start with. As you continue to install more applications, any that support UFW are included in the list of profiles shown when you run the ufw app list command.

If you have completed all of the configurations outlined above, you now have a solid foundation to start installing any other software you need on your new Ubuntu 16.04 server.