Getting started with Ansible

The below was completed on a bare metal server install of EVE-NG.

EVE-NG is built upon Ubuntu 16.04 so all the below is pretty standard Linux/Ansible configuration.

By completing the below you are in effect creating an Ansible control node. Ansible then communicates with devices over SSH (no agent is needed on the managed devices). Below we are also setting netconf on Juniper devices to leverage the native device API.

As you can imagine Ansible (which is a product of RedHat) has extensive documentation and it can be found here - when getting more serious about Ansible then getting your file structure correct and ready for scaling up will reap dividends - check out this Best Practice guide.

Ansible Tower and now Ansible Engine exists where an organisation would like to pay for a supported GUI based controller for many playbooks and users.

Ansible have just (on the 7th Sept’ 2017) open sourced an upstream version of Ansible Tower and it’s here and it’s called AWX. AWX is a great way for you to try Tower or for an organisation to maintain the code and support it themselves.

An alternative open source GUI controller also exists called Semaphore.

Install steps, dependencies and notes.

Your server will need access to the Internet or locally mirrored repositories to complete all these steps with ease!

Create the Ansible user (you can use any username) while logged in as root and give them sudo access:

adduser ansible

usermod -aG sudo ansible

Login in as the user ansible and test; test by listing files in root:

sudo ls -la /root

Create an SSH key (no passphrase) to access devices using an SSH key - this avoids having credentials in playbooks or stored on the Ansible server:

ssh-keygen -t rsa -b 2048

Do initial updates and upgrades and then all the dependency installs:

sudo apt update

sudo apt upgrade

sudo apt install software-properties-common

sudo apt install -y ansible python-dev libxml2-dev libxslt1-dev zlib1g-dev software-properties-common python-setuptools build-essential

pip is the python installer management app:

sudo easy_install pip

sudo pip install ansible junos-eznc junos-netconify

sudo ansible-galaxy install Juniper.junos

This useful utility allows the SSH key created earlier to be installed on managed devices; see here for usage:

sudo pip install git+https://github.com/networkop/ssh-copy-net.git

Edit Ansible hosts file to work with devices:

sudo nano /etc/ansible/hosts

Example Ansible hosts file (setup Linux hosts file for name resolution or use IP addresses in the Ansible hosts file) - quite often referred to as the inventory. Note the use of different groupings - you can create as many of these as you like so you can target a device or group of devices as desired:

[MX]
vmx1 ansible_connection=local
vmx2 ansible_connection=local
vmx3 ansible_connection=local
vmx4 ansible_connection=local
vmx5 ansible_connection=local
vmx6 ansible_connection=local
vmx7 ansible_connection=local

[SRX]
oak01-r1 ansible_connection=local
ash01-r1 ansible_connection=local
oak02-r1 ansible_connection=local
ash02-r1 ansible_connection=local

[JUNIPER:children]
MX
SRX

[JUNIPER:vars]
juniper_user=ansible
juniper_port=830

As mentioned at the top SSH is used to communicate with a device so a user account on the device called ansible is needed with the SSH key and for Juniper devices we will utilise the netconf API to push and pull from the Juniper devices so that also needs configuring; Juniper example config below:

set system login user ansible uid 2001
set system login user ansible class super-user
set system login user ansible authentication ssh-rsa "ssh-rsa blahblahblah ansible"

set system services ssh
set system services netconf ssh

Check the netconf connection:

ssh -s ansible@vmx2 netconf

Some examples of ansible-playbook command line switches that use the ansible hosts file to target or limit devices or queries:

ansible-playbook get.yml -l JUNIPER -t get-config-system

ansible-playbook get.yml --limit=MX --tags=check-netconf

An example of a raw ad-hoc (single Ansible command line string - no playbook) test to a Cumulus VX:

ansible@eve-ng:/etc/ansible/work$ ansible spine01 -u cumulus --ask-pass -m "raw" -a "net show ver"

SSH password:

spine01 | SUCCESS | rc=0 >>
NCLU_VERSION=1.0
DISTRIB_ID="Cumulus Linux"
DISTRIB_RELEASE=3.3.1
DISTRIB_DESCRIPTION="Cumulus Linux 3.3.1"

Shared connection to spine01 closed.

An Ansible expert and colleague pointed out the following if you come across issues with writing to a device via a raw command or in a playbook, this will give you sudo/root equivalent when running actions against the device (as opposed to just logging into the device):

-b, --become        		run operations with become (does not imply password prompting)
-K, --ask-become-pass           ask for privilege escalation password

Another mention of the above issue and fix in a Cumulus forum post.

The get.yml file content is provided below for reference as it’s mentioned above in the Check Connection section:

---
- name: GET
  hosts: JUNIPER
  roles:
  - Juniper.junos
  connection: local
  gather_facts: no

  # Execute tasks (plays) this way "ansible-playbook <path>/GET.yml --tags <tag-name>"
  tasks:
  # Check if a device is NETCONF-aware
  - name: CHECK-NETCONF
    tags: check-netconf
    wait_for: host="" port=""

### JUNOS_GET_CONFIG SECTION
  # Execute "show configuration" and save output to a file
  - name: GET-CONFIG
    tags: get-config
    junos_get_config: host="" port=""
     format=text
     dest="/opt/juniper/_get-config.output"

### JUNOS_CLI SECTION
  # Get list of interfaces and save output to a file
  - name: GET-INTERFACES
    tags: get-interfaces
    junos_cli: host="" port=""
     dest="/opt/juniper/_get-interfaces.output"
     cli="show interfaces terse"

### EOF ###

ansible-playbook command line switches:

Usage: ansible-playbook playbook.yml

Options:
  --ask-vault-pass      ask for vault password
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
                        set additional variables as key=value or YAML/JSON
  --flush-cache         clear the fact cache
  --force-handlers      run handlers even if a task fails
  -f FORKS, --forks=FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path
                        (default=/etc/ansible/hosts) or comma separated host
                        list.
  -l SUBSET, --limit=SUBSET
                        further limit selected hosts to an additional pattern
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  --list-tags           list all available tags
  --list-tasks          list all tasks that would be executed
  -M MODULE_PATH, --module-path=MODULE_PATH
                        specify path(s) to module library (default=None)
  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
                        new vault password file for rekey
  --output=OUTPUT_FILE  output file name for encrypt or decrypt; use - for
                        stdout
  --skip-tags=SKIP_TAGS
                        only run plays and tasks whose tags do not match these
                        values
  --start-at-task=START_AT_TASK
                        start the playbook at the task matching this name
  --step                one-step-at-a-time: confirm each task before running
  --syntax-check        perform a syntax check on the playbook, but do not
                        execute it
  -t TAGS, --tags=TAGS  only run plays and tasks tagged with these values
  --vault-password-file=VAULT_PASSWORD_FILE
                        vault password file
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable
                        connection debugging)
  --version             show program's version number and exit

  Connection Options:
    control as whom and how to connect to hosts

    -k, --ask-pass      ask for connection password
    --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE
                        use this file to authenticate the connection
    -u REMOTE_USER, --user=REMOTE_USER
                        connect as this user (default=None)
    -c CONNECTION, --connection=CONNECTION
                        connection type to use (default=smart)
    -T TIMEOUT, --timeout=TIMEOUT
                        override the connection timeout in seconds
                        (default=10)
    --ssh-common-args=SSH_COMMON_ARGS
                        specify common arguments to pass to sftp/scp/ssh (e.g.
                        ProxyCommand)
    --sftp-extra-args=SFTP_EXTRA_ARGS
                        specify extra arguments to pass to sftp only (e.g. -f,
                        -l)
    --scp-extra-args=SCP_EXTRA_ARGS
                        specify extra arguments to pass to scp only (e.g. -l)
    --ssh-extra-args=SSH_EXTRA_ARGS
                        specify extra arguments to pass to ssh only (e.g. -R)

  Privilege Escalation Options:
    control how and which user you become as on target hosts

    -s, --sudo          run operations with sudo (nopasswd) (deprecated, use
                        become)
    -U SUDO_USER, --sudo-user=SUDO_USER
                        desired sudo user (default=root) (deprecated, use
                        become)
    -S, --su            run operations with su (deprecated, use become)
    -R SU_USER, --su-user=SU_USER
                        run operations with su as this user (default=root)
                        (deprecated, use become)
    -b, --become        run operations with become (does not imply password
                        prompting)
    --become-method=BECOME_METHOD
                        privilege escalation method to use (default=sudo),
                        valid choices: [ sudo | su | pbrun | pfexec | doas |
                        dzdo | ksu | runas ]
    --become-user=BECOME_USER
                        run operations as this user (default=root)
    --ask-sudo-pass     ask for sudo password (deprecated, use become)
    --ask-su-pass       ask for su password (deprecated, use become)
    -K, --ask-become-pass
                        ask for privilege escalation password