The typical way you would perform Network Configuration Backup is by using NCM software such as Solarwinds NCM, Rancid, Oxidized etc. However, you can also utilise Ansible and Git to perform the backups. I know it sounds silly, why would anyone do it? But believe me, it requires very little time and effort to deploy and manage.
In this blog post, I will show you how to perform scheduled configuration backups using Ansible and Git. Ansible will backup the config and Git will perform version control.
I highly recommend you to check out my previous Ansible introduction posts below:


Setting up the environment
I have a very basic set-up with:
- 1 x ASA
- 1 x IOS Router
- 1 x Ansible Control Machine
and GitLab hosted locally.
Ansible
Ansible copies the running configuration from each device daily and saves it into a directory /home/ubuntu/cisco-backups
in the same machine.
Please note that If there are no changes to the running-config then Ansible will not replace the existing file.
Ansible also runs Git commands into that directory so, the changes are committed and pushed to the GitLab repository every day.
Git
Git is a distributed version control system for tracking changes in any set of files. I'm going to use GitLab to manage the repositories in this example. You can also use GitHub or BitBucket.
- Create a new project on GitLab
- Clone the repository to the local host
ubuntu@ubuntu:~$ git clone git@gitlab.packet.lan:root/cisco-backups.git
Cloning into 'cisco-backups'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
You can install GitLab using this guide: Download and install GitLab | GitLab
File structure
ubuntu@ubuntu:~/config_backup$ tree <<< Ansible playbook
.
├── inventory
│ ├── group_vars
│ │ ├── firewall.yml
│ │ └── ios.yml
│ └── hosts
├── playbooks
│ ├── ansible.cfg
│ ├── config_backup.yml
│ └── show_command.yml
└── README.md
Ansible
ubuntu@ubuntu:~/cisco-backups$ tree <<< Backups
Backups
ubuntu@ubuntu:~/config_backup/inventory$ cat hosts
[firewall]
asa ansible_host=192.168.1.62
[ios]
router-1 ansible_host=192.168.1.63
host file
ubuntu@ubuntu:~/config_backup/inventory/group_vars$ cat firewall.yml
---
ansible_network_os: asa
ansible_user: ansible
ansible_password: Cisco123
ansible_become: yes
ansible_become_password: Cisco123
ubuntu@ubuntu:~/config_backup/inventory/group_vars$ cat ios.yml
---
ansible_network_os: ios
ansible_user: ansible
ansible_password: Cisco123
ansible_become: yes
ansible_become_password: Cisco123
group_vars
Please note that in a production environment you shouldn't save the credentials in plain text. Please check out my previous Ansible articles to find out how to use Ansible Vault to encrypt sensitive information.
ubuntu@ubuntu:~/config_backup/playbooks$ cat config_backup.yml
---
- name: FIREWALLS
hosts: firewall
gather_facts: false
connection: network_cli
tasks:
- name: ASA CONFIG
asa_command:
commands: show run
register: output
- name: SAVE ASA CONFIG
copy:
content: "{{ output.stdout[0] }}"
dest: "/home/ubuntu/cisco-backups/show_run_{{ inventory_hostname }}.txt"
- name: IOS ROUTERS
hosts: ios
gather_facts: false
connection: network_cli
tasks:
- name: IOS CONFIG
ios_command:
commands: show run
register: output_router
- name: SAVE IOS CONFIG
copy:
content: "{{ output_router.stdout[0] }}"
dest: "/home/ubuntu/cisco-backups/show_run_{{ inventory_hostname }}.txt"
- name: GIT SECTION
hosts: localhost
tasks:
- name: print time
command: date
register: time
changed_when: false
delegate_to: localhost
run_once: yes
- name: git commands
shell: |
git add .
git commit -m "Device Backup on {{time.stdout}} "
git push
args:
chdir: /home/ubuntu/cisco-backups
delegate_to: localhost
run_once: yes
playbook
Few things to consider
- command: date - Ansible prints out the current date and time and pass it as the Git commit message. So, we can easily find out when a config change was made.
- delegate_to: localhost - We are telling Ansible to run the commands on the localhost
- chdir: - Change the directory
Run the playbook
ubuntu@ubuntu:~/config_backup/playbooks$ ansible-playbook config_backup.yml
PLAY [FIREWALLS] *********************************************************************************************************************************************************************************
TASK [ASA CONFIG] ********************************************************************************************************************************************************************************
ok: [asa]
TASK [SAVE ASA CONFIG] ***************************************************************************************************************************************************************************
changed: [asa]
PLAY [IOS ROUTERS] *******************************************************************************************************************************************************************************
TASK [IOS CONFIG] ********************************************************************************************************************************************************************************
ok: [router-1]
TASK [SAVE IOS CONFIG] ***************************************************************************************************************************************************************************
changed: [router-1]
PLAY [GIT SECTION] *******************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************
ok: [localhost]
TASK [print time] ********************************************************************************************************************************************************************************
ok: [localhost -> localhost]
TASK [git commands] ******************************************************************************************************************************************************************************
changed: [localhost -> localhost]
PLAY RECAP ***************************************************************************************************************************************************************************************
asa : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
router-1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Running the Playbook
Let's verify the config files
As you can see below Ansible copies the running config files into the Git Directory.
ubuntu@ubuntu:~$ ls -l cisco-backups/
total 20
-rw-rw-r-- 1 ubuntu ubuntu 17 Dec 7 15:34 README.md
-rw-rw-r-- 1 ubuntu ubuntu 7715 Dec 7 15:39 show_run_asa.txt
-rw-rw-r-- 1 ubuntu ubuntu 5138 Dec 7 15:39 show_run_router-1.txt
Check the GitLab repository
As you can see below the files are also pushed to GitLab.
Let's make a small config change on both ASA and IOS router and see what happens.
CISCO-ASA# conf ter
CISCO-ASA(config)# interf
CISCO-ASA(config)# interface gi0/2
CISCO-ASA(config-if)# nameif
CISCO-ASA(config-if)# nameif SERVERS
INFO: Security level for "SERVERS" set to 0 by default.
CISCO-ASA(config-if)# ip add
CISCO-ASA(config-if)# ip address 172.16.1.1 255.255.255.0
CISCO-ASA(config-if)# exit
CISCO-ASA(config)# obj
CISCO-ASA(config)# object net
CISCO-ASA(config)# object network VMWARE
CISCO-ASA(config-network-object)# host 172.16.1.10
CISCO-ASA(config-network-object)# end
router-1(config)#access-list 25 permit any
Making Config Changes
Let's run the Playbook again
ubuntu@ubuntu:~/config_backup/playbooks$ ansible-playbook config_backup.yml
Run Playbook
As you can see below Git is showing what has been changed since the last commit.
Removing unwanted lines
As you can see above, Git is registering cryptochecksum:
as a change. You can actually remove that line from the configuration file by using Ansible lineinfile
module. Please make sure to add this task above the GIT SECTION.
- name: Remove Lines from ASA
lineinfile:
path: /home/ubuntu/cisco-backups/show_run_{{ inventory_hostname }}.txt
regexp: 'Cryptochecksum:*'
state: absent
You can set up a cron job to automatically run the playbook daily at specific time. The below will run the playbook each day 1 AM.
0 1 * * * /usr/bin/ansible-playbook /home/ubuntu/config_backup/playbooks/config_backup.yml
cron job
Thanks for reading.
As always, your feedback and comments are more than welcome.