Ansible Automation with Cisco ASA Multi-Context Mode

I thought I’d share my experience using Ansible and Cisco ASA firewalls in multi-context mode. Right from the beginning I had a few issues deploying the configuration and the switch between the different security context didn’t work well. I got the error you see below when I tried to run a playbook. Other times the changeto context didn’t work well and applied the wrong config:

[email protected]:~$ ansible-playbook -i inventory site.yml --ask-vault-pass
Vault password:

PLAY [all] ***************************************************************************************************************************************************************************

TASK [hostname : set dns and hostname] ***********************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: error: [Errno 61] Connection refused
fatal: [fwcontext01]: FAILED! => {"changed": false, "err": "[Errno 61] Connection refused", "msg": "unable to connect to socket"}
ok: [fwcontext02]

TASK [interfaces : write interfaces config] ******************************************************************************************************************************************
ok: [fwcontext02]


After a bit of troubleshooting I found a workaround to limit the amount of processes Ansible use and set this limit to one in the Ansible.cfg. The default is five processes if forks is not defined as far as I remember.

inventory = ./inventory
forks = 1

In the example inventory file, the “inventory_hostname” variable represents the security context and as you see the “ansible_ssh_host” is set to the IP address of the admin context:

fwcontext01 ansible_ssh_host= ansible_ssh_port=22 ansible_ssh_user='ansible' ansible_ssh_pass='cisco'
fwcontext02 ansible_ssh_host= ansible_ssh_port=22 ansible_ssh_user='ansible' ansible_ssh_pass='cisco'

When you run the playbook again you can see that the playbook runs successfully but deploys the changes one by one to each firewall security context, the disadvantage is that the playbook takes much longer to run:

[email protected]:~$ ansible-playbook site.yml

PLAY [all] ***************************************************************************************************************************************************************************

TASK [hostname : set dns and hostname] ***********************************************************************************************************************************************
ok: [fwcontext01]
ok: [fwcontext02]

TASK [interfaces : write interfaces config] ******************************************************************************************************************************************
ok: [fwcontext01]
ok: [fwcontext02]

Example site.yml


- hosts: all
  connection: local
  gather_facts: 'no'

      username: "{{ ansible_ssh_user }}"
      password: "{{ ansible_ssh_pass }}"
      host: "{{ ansible_ssh_host }}"

    - interfaces

In the example Interface role you see that the context is set to “inventory_hostname” variable:


- name: write interfaces config
    src: "templates/interfaces.j2"
    provider: "{{ cli }}"
    context: "{{ inventory_hostname }}"
  register: result

- name: enable interfaces
    parents: "interface {{ item.0 }}"
    lines: "no shutdown"
    match: none
    provider: "{{ cli }}"
    context: "{{ inventory_hostname }}"
  when: result.changed
    - "{{ interfaces.items() }}"

After modifying the forks, the Ansible playbook runs well with Cisco ASA in multi-context mode, like mentioned before it is a bit slow to deploy the configuration if I compare this to Cumulus Linux or any other Linux system.

Please share your feedback.

Leave a comment

Setup Juniper ISG NSRP cluster

This post describes how to rebuild a Juniper NSRP Cluster if the first Juniper firewall is already configured for NSRP.
Please make sure you have the following prerequisite on both Firewalls.

Minimum software and hardware requirements for configuring Active / Passive NSRP:

  • Firewall’s with identical ScreenOS versions and license keys
  • Firewall’s with identical hardware
  • At least one interface on each firewall to be configured in the HA zone, which will be used for carrying control channel information

Configuration steps on the unconfigured Firewall.

Configure the Interface(s) for HA

If possible it makes sense to use the same Interface as used on the other device.

set interface ethernet0/4 zone HA

Configure the NSRP cluster id:

set nsrp cluster id 1

Both firewalls in the cluster must have the same Cluster ID number.

IMPORTANT: Other NSRP firewall pairs on the same segment must have a different set of cluster ids. Once the cluster id is set to a value, all the security interfaces will become part of the VSD-group 0, by default.

Configure cluster name for NSRP:

To define a single name for all cluster members, type the following CLI command:

set nsrp cluster name <name_str>
set nsrp vsd-group id <number> priority <number>

IMPORTANT: Make sure that the desired STANDBY firewall has a HIGHER priority configured than the preferred master. The firewall with the lower priority will be the active master in the cluster!

Physical connection:

Connect only the HA link cable to the interface that is configured for the HA zone.

Check the nsrp cluster status:

You can check the nsrp cluster status via the configuration GUI or via CLI.

To check the NSRP cluster status via GUI connect to the actual master and navigate to Reports > System Log > Event and search for NSRP related entries.

To check the NSRP cluster status via CLI please connect to the actual standby via console. You can check the status with the following command:

get nsrp cluster

Synchronize the configurations:

To synchronize the configuration from the active to the standby unit, please connect to the standby unit via console and execute the following command:

exec nsrp sync global-config save

The following will be reported shortly after you enter the above command:

load peer system config to save
firewall-B(B)-> Save global configuration successfully.
firewall-B(B)-> Save local configuration successfully.
firewall-B(B)-> Done.
firewall-B(B)-> Please reset your box to let cluster configuration to take effect!

Reset the Firewall:

IMPORTANT:  If you are prompted to save the configuration after you enter the reset command, answer n (No).  Then, proceed with the reboot by answering y (Yes).

firewall-B(B)-> reset
firewall-B(B)-> Configuration modified.  Save? [y]/n n
firewall-B(B)-> System reset.  Are you sure? y/[n] y

Check if the configurations are in sync:

Please execute the following command via CLI (console connection) on the backup firewall to check if the configurations are in sync:

exec nsrp sync global-config check-sum

Physical connection:

Please connect all other interfaces in the correct order to the standby unit.

Initial manual failover:

exec nsrp vsd-group 0 mode ineligible

Command reference:


get nsrp cluster Show cluster info
get nsrp monitor Show list of monitored interfaces
get nsrp vsd id 0 Show VSD id 0
get counters ha Show HA interface hardware counters
exec nsrp sync global-config check-sum Allows you to see if the cluster configs are syncronised
exec nsrp sync global save Sync’s the nodes.A reboot is required to complete the update.
exec nsrp vsd-group 0 mode Fails over the cluster. Run this command on the Master node.

Current Settings / Values

get envar get environment variable
get config get device configuration
get system get system information
get arp get arp cache
get route get routing table

Just tested new Cisco ASA 8.3 (Update)

It was a big suprise that Cisco changed so many things in the new IOS version for the ASA. Remember it is only an minor release update i would expect these changes for an major update but anyway they did a good work.

The new group objects what they implementent is very nice. It make the work much easier and you have a better overview about the NAT configuration like before because they move it to the actual network object.

Here an example how nat works in the network object:

object network web-01-external

object network web-01-frontside
description Web Server Node 1
nat (inside,outside) static web-01-external