Ansible: Your Go-To Tool For IT Automation

Ansible: Your Go-To Tool For IT Automation

An introduction to Ansible and how to use it for your IT automation purposes

What is Ansible ?

Ansible is an open-source software provisioning, configuration management and an application-deployment tool for enabling infrastructure as code. With the help of Ansible almost any kind of task can be carried out on any number of hosts with the help of commands run on one single master host.

It runs on many Unix-like systems, and can configure both Unix-like systems as well as Microsoft Windows. Just because using Ansible one can provide IT automation with the many features it offers for infrastructure as code, it has many alternatives. But Ansible being one of the widely used tools still stands out amidst the competition in the DevOps lifecycle. Feel free to explore the docs

It can be used for:

  • Configuration Management
  • Application Deployment
  • Orchestration
  • Security and Compliance

Some of its alternatives are:

How Ansible works

Ansible works by connecting to your nodes and pushing out small programs, called "Ansible modules" to them. These programs are written to be resource models of the desired state of the system and Ansible then executes these modules (over SSH by default) and removes them when finished.

Ansible Terminologies

  • Inventory - Ansible works against multiple managed nodes or “hosts” in your infrastructure at the same time using a list or group of lists known as inventory. Basically in this we can group servers under one name which will help running commands on a group of servers together.

  • Playbook - Ansible Playbooks offer a repeatable, re-usable and simple configuration management along with a multi-machine deployment system, one that is well suited to deploying complex applications.

  • Role - Roles are units of organisation in Ansible; assigning a role to a group of hosts (or a set of groups, or host patterns, and so on) implies that they should implement a specific behaviour. A role may include applying certain variable values, certain tasks, and certain handlers or just one or more of these things.

  • Task - Playbooks exist to run tasks. Tasks combine an action (a module and its arguments) with a name and optionally some other keywords.

  • Handlers - Handlers are tasks that only run when notified. By default, handlers run after all the tasks in a particular play have been completed.

About the Article

In this article, we will deal with the configuration management part. Whenever we start working on new servers we follow a set of principles for security purposes, these could be:

  • Disabling IPv6
  • Changing SSH default Port
  • Initial Firewall configuration
  • SSH keys management

It can be done manually when less number of servers are booted but will prove to be tiresome when a configuration is required on large number of servers. Ansible helps with automating and steamlining the entire workflow.

Download Ansible on a master node.

  • Install Ansible only on the master node using the code for CentOS:
sudo yum update 
yum install ansible
  • Install Ansible only on the master node using the code for Ubuntu:
sudo apt update 
sudo apt install ansible
  • Install Ansible only on the master node using the code for AWS EC2:
sudo amazon-linux-extras install ansible2

Establish a connect between controller and to-be-controlled nodes

  • Create ssh-key on controller node using the code given below:
ssh-keygen
  • Copy the output by entering the following snippet in your console:
cat .ssh/id_rsa.pub

Create Inventory

Here we define all the servers that require management configurations and edit the /etc/ansible/hosts

Add these lines as per requirement:

[server_grp1]
userserver1 ansible_host=<IP address of a server>
userserver2 ansible_host=<IP address of a server>

[server_grp2]
userserver3 ansible_host=<IP address of a server>
userserver4 ansible_host=<IP address of a server>

This way you can group different categories of servers under different heads to run tasks exclusively.

Note: For this article I have only one controller and controlled node

Test your connection by entering the following snippet in your console:

ansible -m ping all

If the ssh is configured properly you will get a sucess message.

Create tasks

Now we have to add all required tasks.yaml files inside the /etc/ansible/role/tasks. The basic structure of tasks.yaml is given below:

- hosts: <server group>
  gather_facts: <false/true>
  tasks:
    - name: <name of task>
       param1: config1
...

host - define the groups chosen from inventory for this task.

gather_facts - gathers system level information from the controlled nodes.

tasks - define the workflow to be carried out on the controlled nodes.

Disabling IPv6

Why disabling IPv6 is required ?

Since most services bind to 0.0.0.0 and [::]:[port] (every interface), these services are also available over IPv6. Though not being used, some of your programs open listening sockets on IPv6 (and IPv4 as well) and will process packets coming in and if it is not being used, it can altogether be disabled or be put under firewall configuration.

The code snippet to disable-ipv6.yaml is given below:

- hosts: servers
  gather_facts: false
  tasks:
    - name: Assign Port
      set_fact:
        ansible_port: <ssh_port_to_connect_to_other_nodes>

    - name: Disable IPv6 with sysctl
      sysctl: name={{ item }} value=1 state=present reload=yes
      with_items:
        - net.ipv6.conf.all.disable_ipv6
        - net.ipv6.conf.default.disable_ipv6
        - net.ipv6.conf.lo.disable_ipv6

Here Ansible will use ansible_port to connect to other nodes by using sysctl (sysctl is used to modify kernel parameters at runtime) to disable IPv6 and then will reload the service. This code snippet will pickup items from with_items and set its value to 1 and reload sysctl:

ansible-playbook disable-ipv6.yaml

Change SSH Port

Why changing SSH port is required ?

As everyone knows that default ssh port is Port 22, so just to add as a security feature on top of SSH we can change the default port to a different value to reduce further chances of unauthorised access via SSH. Enter the following code snippet into your console to change-ssh-port.yaml:

- hosts: servers
  gather_facts: false
  vars:
    desired_port: <Enter desired port>
    default_port: <Enter default port>
  tasks:
    - name: check if ssh is running on {{ desired_port }}
      delegate_to: localhost
      wait_for:
        port: "{{ desired_port }}"
        host: "{{ ansible_host }}"
        timeout: 10
      ignore_errors: true
      register: desired_port_check

    - name: check if ssh is running on {{ default_port }}
      delegate_to: localhost
      wait_for:
        port: "{{ default_port }}"
        host: "{{ ansible_host }}"
        timeout: 10
      ignore_errors: true
      register: default_port_check

    - Enter fail:
        msg: "ssh is not running (or is running on an unknown port)"
      when: default_port_check is failed and desired_port_check is failed

    - when: default_port_check is success
      block:
        - debug:
            msg: "ssh is running on default port"

        - name: configure ansible to use port {{ desired_port }} Part 1
          set_fact:
            ansible_port: "{{ default_port }}"

        - name: configure ansible to use port {{ desired_port }} Part 2
          lineinfile:
            dest: "/etc/ssh/sshd_config"
            regexp: "^Port"
            line: "Port {{ desired_port }}"
          notify: "Restart sshd"

    - when: desired_port_check is success
      block:
        - debug:
            msg: "ssh is running on desired port"

    - name: Flush Handlers
      meta: flush_handlers

  handlers:
    - name: Restart sshd
      service:
        name: sshd
        state: restarted

Here in this code snippet, we first to try to verify which port SSH connection can be established and accordingly set the value default_port_check and desired_port_check. If default_port_check is successful, change the ssh configuration remotely and execute handlers to restart the sshd service. If the desired_port_check is success then the changes are not required. Run the following code to get the required SUCCESS message:

ansible-playbook change-ssh-port.yaml

Firewall configuration

Why is firewall required ?

Firewall is a service that helps a user to fully manage the inbound and outbound traffic to a server. It is the most important and basic requirement for security on the server and it is required that it is properly configured. Enter the following code for firewall-conf.yaml:

- hosts: servers
  gather_facts: false
  tasks:
    - name: Assign Port
      set_fact:
        ansible_port: <ssh_port_to_connect_to_other_nodes>

    - name: install firewalld
      action: yum name=firewalld state=installed

    - name: Enable firewalld on system reboot
      service: name=firewalld enabled=yes

    - name: Start service firewalld, if not started
      service:
        name: firewalld
        state: started

    - name: Add ports
      firewalld:
        permanent: yes
        immediate: yes
        port: "{{item.port}}/{{item.proto}}"
        state: "{{item.state}}"
        zone: "{{item.zone}}"
      with_items:
       - {port: "80", proto: "tcp", state: "enabled", zone: "public" }
       - {port: "443", proto: "tcp", state: "enabled", zone: "public" }
       - {port: "10050", proto: "tcp", state: "enabled", zone: "internal" }

    - name: Add sources
      firewalld:
        permanent: yes
        immediate: yes
        source: "{{item.source}}"
        state: "{{item.state}}"
        zone: "{{item.zone}}"
      with_items:
        - {source: "<source you want>", state: "enabled", zone: "internal"}

    - name: Add Rich Rules
      firewalld:
        permanent: yes
        immediate: yes
        rich_rule: "{{ item }}"
        state: enabled
      with_items:
       - 'rule family="ipv4" source address="<reqd_address>" port port="<reqd_port>" protocol="tcp" accept'
       - 'rule family="ipv4" source address="<reqd_address>" port port="<reqd_port>" protocol="tcp" accept'
       - 'rule family="ipv4" source address="<reqd_address>" port port="<reqd_port>" protocol="tcp" accept'
       - 'rule family="ipv4" source address="<reqd_address>" port port="<reqd_port>" protocol="tcp" accept'

Here we first install and enable the firewalld service and then we can add ports, sources and rich rules as per the use case requirement. Run the following code snippet:

ansible-playbook firewall-conf.yaml

SSH Keys management

Managing SSH keys on server is a very tedious task and especially when it comes to adding and removing keys on the server. Initially people resort to this manually but as and when the product scales and new servers and are added and team members are added it becomes difficult. However, this can be automated with help Ansible by storing all the required keys in a file on Ansible master/controller server. Enter the following code snippet to add-keys.yaml:

- hosts: servers
  gather_facts: false
  tasks:
    - name: Assign Port
      set_fact:
        ansible_port: <ssh_port_to_connect_to_other_nodes>

    - name: Add keys
      authorized_key:
        user: user
        key: '{{ item }}'
        state: present
      with_file:
        - <path_to_stored_keys>
        - <path_to_stored_keys>
        - <path_to_stored_keys>

Enter the following code snippet to remove-keys.yaml:

- hosts: servers
  gather_facts: false
  tasks:
    - name: Assign Port
      set_fact:
        ansible_port: <ssh_port_to_connect_to_other_nodes>

    - name: Add keys
      authorized_key:
        user: ec2-user
        key: '{{ item }}'
        state: absent
      with_file:
        - <path_to_stored_keys>

Run these yaml files as and when required to add and remove ssh keys remotely using Ansible.

Conclusion

I hope this article has proven to be a good introduction for you to start your Ansible journey. Here are some added advantages that Ansible provides:

  • It is open-source.
  • Ansible is a smart tool.
  • It keeps track of the last changes it did to a file which helps faster processing and avoiding repetitive tasks.
  • Ansible is agentless because of which it uses a secure shell to connect to all other controlled nodes.

  • As you don’t need to install any extra software, there’s more room for application resources on your server.

I hope this read up will interest you to explore Ansible and I would highly recommend you to use this very popular and versatile tool !! 😊😊