Ansible ASA Playbook (asa_config and asa_acl): Cisco ASA access-list

Like in my previous post in the new development version 2.2. from Ansible are new IOS and ASA core modules.

Here an example of the asa_config and asa_acl module to create and object-group in the first step and create the inside create access-list:

- name: Cisco ASA access-list config
  connection: local
  hosts: firewall
  gather_facts: false
  vars:
    cli:
      username: "{{ username }}"
      password: "{{ password }}"
      host: "{{ device_ip }}"
      authorize: yes
      auth_pass: cisco
  tasks:
    - name: create object group
      asa_config:
        lines:
          - network-object host 10.1.0.1
          - network-object host 10.1.0.2
          - network-object host 10.1.0.3
        parents: ['object-group network dummy-group']
        provider: "{{ cli }}"
#      register: result

    - name: configure access-list
      asa_acl:
        lines:
          - access-list acl_inside extended permit tcp object-group dummy-group any eq www
          - access-list acl_inside extended permit udp object-group dummy-group any eq domain
          - access-list acl_inside extended deny ip any any
        before: clear configure access-list acl_inside
        match: strict
        replace: block
        provider: "{{ cli }}" 
#      register: result

    - debug: var=result

Here output when you run the playbook the first time:

ansible-playbook cisco/asa_access-list_config.yml -i cisco/hosts

PLAY [Cisco ASA access-list config] ********************************************

TASK [create object group] *****************************************************
changed: [fw1]

TASK [configure access-list] ***************************************************
changed: [fw1]

TASK [debug] *******************************************************************
ok: [fw1] => {
    "result": "VARIABLE IS NOT DEFINED!"
}

PLAY RECAP *********************************************************************
fw1                        : ok=3    changed=2    unreachable=0    failed=0

Here the output then you run the playbook a second time, you see nothing is changed:

ansible-playbook cisco/asa_access-list_config.yml -i cisco/hosts

PLAY [Cisco ASA access-list config] ********************************************

TASK [create object group] *****************************************************
ok: [fw1]

TASK [configure access-list] ***************************************************
ok: [fw1]

TASK [debug] *******************************************************************
ok: [fw1] => {
    "result": "VARIABLE IS NOT DEFINED!"
}

PLAY RECAP *********************************************************************
fw1                        : ok=3    changed=0    unreachable=0    failed=0

Read my new post about an Ansible Playbook for Cisco ASAv Firewall Topology

12 Replies to “Ansible ASA Playbook (asa_config and asa_acl): Cisco ASA access-list”

  1. First thank you for post this works great!

    Do you have any suggestions how to update multiple object-groups in asa with single playbook?

    tasks:
    – name: create object group
    asa_config:
    lines:
    – network-object host 10.1.0.1
    – network-object host 10.1.0.2
    – network-object host 10.1.0.3
    parents: [‘object-group network dummy-group’]
    provider: “{{ cli }}”
    # register: result

    so this works ok for: object-group network dummy-group, but if i have another one that i would like to update, how would the format be?

    For example:

    tasks:
    – name: create object group
    asa_config:
    lines:
    – network-object host 10.1.0.1
    – network-object host 10.1.0.2
    – network-object host 10.1.0.3
    parents: [‘object-group network dummy-group’]
    – network-object host 192.168.0.1
    – network-object host 192.168.0.2
    parents: [‘object-group network dummy-group2’]

    Thank you!
    Eimis

    1. Hi Eimis,
      I was working on a complete Ansible Playbook for a Cisco ASA, is actually my next blog post I am currently working on, will publish it beginning of next week.

      But you can have a look already at the my Github repo for this post:
      https://github.com/berndonline/asa-lab-provision

      For creating objects and object-groups I use a Jinja2 template instead of lines:

      – name: include objects variables
      include_vars:
      file: “group_vars/objects.yml”

      – name: create objects
      asa_config:
      src: “templates/objects.j2”

      Jinja2 template objects.j2:

      {% if objects is defined %}
      {% for object, value in objects.items() %}
      object network {{ object }}
      {% if value and ‘host’ in value %}
      host {{ value[‘host’] }}
      {% endif %}
      {% if value and ‘subnet’ in value %}
      subnet {{ value[‘subnet’] }} {{ value[‘mask’] }}
      {% endif %}
      {% if ‘alias’ in value %}
      description {{ value.alias }}
      {% endif %}
      {% endfor %}
      {% endif %}

      Have a look at my repo and come back next week when I am finished with my new post.

      Best,
      Bernd

  2. Hi!

    Thanks for the example above works nicely. I’m trying to create a local username task, but I keep getting an error. Can you help me out on this one? here’s example:


    – name: Cisco ASA access-list config
    connection: local
    hosts: firewall
    gather_facts: false

    vars:
    cli:
    host: 192.168.0.99
    authorize: yes
    auth_pass: xxxxxx

    tasks:
    – name: create local user
    asa_config:
    lines:
    – username test password testing privilege 15
    provider: “{{ cli }}”
    #
    register: print_output
    – debug: var=print_output

    I’m passing my ssh creds as arguments.

    Thanks!
    Fabian

    1. Hi Fabian,
      Ansible works a bit differently you should have a separate inventory file when you run a playbook. You can also group your devices in the inventory file if needed but there is no need to have the credentials in the inventory is just something what I do because of Ansible Vault to encrypt the inventory file.

      Here an example inventory:

      firewall ansible_ssh_host=192.168.0.1 ansible_ssh_port=22 ansible_ssh_user='cisco' ansible_ssh_pass='cisco'
      

      Here your playbook to create a user account:

      ---
      - hosts: all
        connection: local
        gather_facts: 'false'
      
        vars:
          cli:
            username: "{{ ansible_ssh_user }}"
            password: "{{ ansible_ssh_pass }}"
            host: "{{ ansible_ssh_host }}"
            authorize: 'yes'
            auth_pass: cisco
        tasks:
          – name: create local user
            asa_config:
              lines:
                - username test password testing privilege 15
              provider: "{{ cli }}"
            register: result
      
          – debug: var=result
      

      Now just execute the playbook:

      ansible-playbook ./create_user.yml -i ./inventory 
      

      I hope that helps you to continue?
      Best,
      Bernd

  3. Hi Bernd,

    Thank you for replies and suggestions, have another question maybe you already have a playbook for it that would be great, for example modify class-map etc., if i have multiline update to class-map etc., it fails for me, here is examples of lines i need to execute,

    “` – access-list global_mpc_1 line 1 extended deny ip any object-group Internal-Networks
    – access-list global_mpc_1 line 2 extended permit ip any any
    – class-map sfr
    – match access-list global_mpc_1
    – policy-map global_policy
    – no description sfr
    – class sfr
    – sfr fail-open
    “`

    simple stuff like multiline access-list modifications i can those to work, but something more advanced when you enter into class-maps etc., wont seem to execute the rest of the commands, i am guessing ansible thinks its still on main conf t line.

    thanks again!

    1. Hello Eimis,

      Updating multi line class maps for access lists is a problem I also faced. I never really got this to work with the older ansible versions (2.4.x).

      Here is a role I have written for various policyframe work configuration but doesn’t really work replacing multi line objects:

      https://github.com/berndonline/asa-lab-provision/blob/master/roles/policy-framework/tasks/main.yml

      I have not tried it since then and the ansible asa network module might be not the right way and use instead the REST API of the ASA.

      But if you find a way please let me know I am very interested getting this working.

      Best,
      Bernd

  4. Hi Bernd,

    I am running ansible 2.9.27. According to https://docs.ansible.com/ansible/2.9/modules/asa_config_module.html one should use connection: network_cli instead of the old provider object.

    So this is my task:

    – name: Create VLAN interface
    asa_config:
    match: line
    parents:
    – Interface GigabitEthernet0/2.{{ vlan }}
    lines:
    – description {{ short }}
    – vlan {{ vlan }}
    – nameif {{ short }}
    – security-level 10
    – ip address 172.27.{{ vlan }}.3 255.255.255.0

    (ansible_connection: network_cli is located in group_vars)

    When I run my playbook twice, I always get changed=1. The reason is located here: /usr/lib/python2.7/dist-packages/ansible/modules/network/asa/asa_config.py

    # send the configuration commands to the device and merge
    # them with the current running config
    if not module.check_mode:
    load_config(module, commands)
    result[‘changed’] = True

    (ANSIBLE_METADATA = {‘metadata_version’: ‘1.1’,’status’: [‘preview’],’supported_by’: ‘community’})

    Why wasn’t this the case in your situation?

    Best regards,
    Lukas

    1. Hi Lukas,
      Sorry I can’t remember this, I haven’t used Ansible for a couple of years and the modules over time have changed quite a lot.
      Good luck finding a config which hopefully works.
      Take care,
      Bernd

Leave a Reply to eimis Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.