In October 2019 as part of the Red Hat Ansible Engine 2.9 release, the Ansible Network Automation team introduced the first resource modules. These opinionated network modules make network automation easier and more consistent for those automating various network platforms in production. The goal for resource modules is to avoid creating and maintaining overly complex jinja2 templates for rendering and pushing network configuration.
This blog post covers the newly released ios_acls resource module and how to automate manual processes associated with switch and router configurations. These network automation modules are used for configuring routers and switches from popular vendors (but not limited to) Arista, Cisco, Juniper, and VyOS. The access control lists (ACLs) network resource modules are able to read ACL configuration from the network, provide the ability to modify and then push changes to the network device. These opinionated network resource modules make network automation easier and more consistent for those automating various network platforms in production. I’ll walk through several examples and describe the use cases for each state parameter (including three newly released state types) and how these are used in real world scenarios.
The Certified Content Collection
This blog uses the cisco.ios Collection maintained by the Ansible team, but there are other platforms that also have ACL resource modules, such as arista.eos, junipernetworks.junos, and vyos.vyos.
- How to obtain the certified (supported) and upstream (community) Collection
The upstream community Collection can be found on Ansible Galaxy: https://galaxy.ansible.com/cisco/ios
The downstream supported Collection can be found on Automation Hub:
https://cloud.redhat.com/ansible/automation-hub/cisco/ios
For more information on Ansible Content Collections, please refer to the following documentation: https://docs.ansible.com/ansible/latest/user_guide/collections_using.html
Before starting, let’s quickly explain the rationale behind the naming of the network resource modules. The newly added ACLs modules will be plural (eos_acls, ios_acls, junos_acls, nxos_acls, iosxr_acls). The older singular form modules (e.g. ios_acl, nxos_acl) will be deprecated over time. This naming change was done so that those using existing network modules would not have their Ansible Playbooks stop working and have sufficient time to migrate to the new network automation modules.
Platform support
This module is also available for the following Ansible-maintained platforms on both Automation Hub (supported) and Galaxy (community):
Platform |
Full Collection path |
Automation Hub Link (requires subscription) |
Ansible Galaxy Link |
Arista EOS |
arista.eos.eos_acls |
||
Cisco IOS |
cisco.ios.ios_acls |
||
Cisco IOSXR |
cisco.iosxr.iosxr_acls |
||
Cisco NXOS |
cisco.nxos.nxos_acls |
||
Juniper JunOS |
junipernetworks.junos.junos_acls |
||
VyOs |
vyos.vyos.vyos_firewall_rules |
Getting started - Managing the ACL configuration with Ansible
An access control list (ACL) provides rules that are applied to port numbers and/or IP addresses permitted to transit or reach that network device. ACL order of access control entry (ACE) is critical because the ACEs sequence/order route decides which rules are applied to inbound/outbound network traffic.
An ACL resource module provides the same level of functionality that a user can achieve when configuring manually on the Cisco IOS device. But combined with Ansible facts gathering and resource module approach, this is more closely aligned with how network professionals work day to day.
I’ll be using an IOS router with version 15.6(3)M2 for all the configuration of this post. Below is the initial state of router ACLs configuration and currently there are already active ACLs configured on the device.
Network device configuration
cisco#sh access-lists
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list test_acl
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
Using state gathered - Building an Ansible inventory
Resource modules allow the user to read in an existing network configuration and convert that into a structured data model. The state: gathered is the equivalent for gathering Ansible facts for this specific resource. This example will read in the existing network configuration and store it as a flat file.
Ansible Playbook Example
Here is an Ansible Playbook example of using state: gathered and storing the result as YAML into host_vars. If you are new to the concept of Ansible inventory and want to learn more about group_vars and host_vars, please refer to the Ansible User Guide: Inventory.
---
- name: convert configured ACLs to structured data
hosts: cisco
gather_facts: false
tasks:
- name: Use the ACLs resource module to gather the current config
cisco.ios.ios_acls:
state: gathered
register: acls
- name: Create inventory directory
file:
path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}"
state: directory
- name: Write the ACL configuration to a file
copy:
content: "{{ {‘acls’: acls['gathered']} | to_nice_yaml }}"
dest: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/acls.yaml"
Execute the Ansible Playbook with the ansible-playbook command:
ansible-playbook example.yml
Examine File contents
Here is the data structure that was created from reading in an existing configuration:
$ cat lab_inventory/host_vars/rtr2/acls.yaml
acls:
- acls:
- aces:
- destination:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
dscp: ef
grant: deny
protocol: icmp
protocol_options:
icmp:
traceroute: true
sequence: 10
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
ttl:
eq: 10
- destination:
host: 198.51.110.0
port_protocol:
eq: telnet
grant: deny
protocol: tcp
protocol_options:
tcp:
ack: true
sequence: 20
source:
host: 198.51.100.0
acl_type: extended
name: '110'
- aces:
- destination:
address: 192.0.3.0
port_protocol:
eq: www
wildcard_bits: 0.0.0.255
grant: deny
option:
traceroute: true
protocol: tcp
protocol_options:
tcp:
fin: true
sequence: 10
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
ttl:
eq: 10
acl_type: extended
name: test_acl
afi: ipv4
- acls:
- aces:
- destination:
any: true
port_protocol:
eq: telnet
dscp: af11
grant: deny
protocol: tcp
protocol_options:
tcp:
ack: true
sequence: 10
source:
any: true
port_protocol:
eq: www
name: R1_TRAFFIC
afi: ipv6
In the above output (and future reference):
- afi refers to address family identifier, either IPv4 or IPv6
- acls refers to access control lists, and returns a list of dictionaries (ACEs)
- aces refers to access control entry, or the specific rule and sequence
Using state merged - Pushing configuration changes
The state merged will take your Ansible configuration data (for example Ansible variables) and merges them into the network device’s network configuration. This will not affect existing configuration not specified in your Ansible configuration data. Let’s walk through an example.
Modify stored file
We will modify the flat file created in the first example. We will then create an Ansible Playbook to merge this new configuration into the network device’s running configuration.
Reference link: https://gist.githubusercontent.com/justjais/bb2a65c373ab4e64d1eeb47bc425c613/raw/056d2a6a44910863cbbbf38cad2273435574db84/Merged.txt
acls:
- afi: ipv4
acls:
- name: std_acl
acl_type: standard
aces:
- grant: deny
source:
address: 192.168.1.200
- grant: deny
source:
address: 192.168.2.0
wildcard_bits: 0.0.0.255
- name: 110
aces:
- grant: deny
sequence: 10
protocol_options:
icmp:
traceroute: true
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
destination:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
dscp: ef
ttl:
eq: 10
- grant: deny
protocol_options:
tcp:
ack: true
source:
host: 198.51.100.0
destination:
host: 198.51.110.0
port_protocol:
eq: telnet
- name: test
acl_type: extended
aces:
- grant: deny
protocol_options:
tcp:
fin: true
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
destination:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: www
option:
traceroute: true
ttl:
eq: 10
- name: 123
aces:
- grant: deny
protocol_options:
tcp:
ack: true
source:
address: 198.51.100.0
wildcard_bits: 0.0.0.255
destination:
address: 198.51.101.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
tos:
service_value: 12
- grant: deny
protocol_options:
tcp:
ack: true
source:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
destination:
address: 192.0.4.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: www
dscp: ef
ttl:
lt: 20
- afi: ipv6
acls:
- name: R1_TRAFFIC
aces:
- grant: deny
protocol_options:
tcp:
ack: true
source:
any: true
port_protocol:
eq: www
destination:
any: true
port_protocol:
eq: telnet
dscp: af11
Ansible Playbook Example
---
- name: Merged state play
hosts: cisco
gather_facts: false
tasks:
- name: Merge ACLs config with device existing ACLs config
cisco.ios.ios_acls:
state: merged
config: "{{ acls }}"
Once we run the respective Merge play, all of the provided parameters will be configured on the Cisco IOS router with Ansible changed=True
Network device configuration
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
If we dig slightly into the device output, we make the following observations:
- Based on the AFI value, it’s decided by the module to call IP/IPV6 access-lists.
- The ‘acl_type’ key is required for named ACLs.
- For ACLs identified by a number rather than a name, the ‘acl_type’ is derived from the platform’s documented ACL number ranges. (eg Standard = 1–99 and 1300–1999, Extended = 100–199 and 2000–2699, etc)
- If the sequence number is not mentioned in the ACE, it will be configured based on the order provided in the play.
- With the second run, the respective Merge Play runs again and Ansible charm of Idempotency comes to picture, and if nothing’s changed, play run results into changed=False, which confirms to the user that all of the provided configurations in the play are already configured on the IOS device.
Using state replaced - Pushing configuration changes
The replaced parameter enforces the data model on the network device for each configured ACL/ACE. If we modify any of the ACL/ACEs, it will enforce all the parameters this resource module is aware of. To think of this another way, the replaced parameter is aware of all the commands that should and shouldn’t be there.
For this scenario, an ACL with some ACEs is already configured on the Cisco IOS device, and now the user wants to update the ACL with a new set of ACEs and discard all the already configured ACL ACEs. The resource module that replaced “s” will replace ACL existing ACEs with a new set of ACEs given as input by the user.
Ref gist link: https://gist.githubusercontent.com/justjais/bb2a65c373ab4e64d1eeb47bc425c613/raw/056d2a6a44910863cbbbf38cad2273435574db84/Replaced.txt
acls:
- afi: ipv4
acls:
- name: 110
aces:
- grant: deny
protocol_options:
tcp:
syn: true
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
destination:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: www
dscp: ef
ttl:
eq: 10
- name: 150
aces:
- grant: deny
sequence: 20
protocol_options:
tcp:
syn: true
source:
address: 198.51.100.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
destination:
address: 198.51.110.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
dscp: ef
ttl:
eq: 10
Ansible Playbook Example
---
- name: Replaced state play
hosts: cisco
gather_facts: false
tasks:
- name: Replace ACLs config with device existing ACLs config
cisco.ios.ios_acls:
state: replaced
config: "{{ acls }}"
With the above play, the user is replacing the 123 extended ACL with the provided ACL ACEs configuration and also configuring the 150 extended new ACL ACEs.
Before running the replaced play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
With replaced Play run, commands that are fired:
- ip access-list extended 110
- no 10
- no 20
- deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
- ip access-list extended 150
- 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
After running the replaced play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list 150
20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
If we dig the output briefly, we may have following observation:
- replaced will negate all the pre-existing ACEs under the input ACL and then apply the configuration provided as input in the play. The same behaviour can be seen in the commands output above for numbered ACL 123, where the pre-existing ACEs at sequence 10 and 20 are negated first before applying the changes for newer ACE configuration.
- For the 150 extended ACL ACEs, since it wasn’t already pre-configured on the device, the module goes ahead and applies the ACE configuration provided as input in the play. One thing to note here is that in the play input configuration value to sequence is mentioned as 20, and as a result ACE is configured on sequence 20 instead of 10, which would have been the case if value to sequence wasn’t provided by the user.
With the second run of the above play, changed comes as false, which satisfies the Ansible idempotency.
Using state overridden - Pushing configuration changes
For this example, we will mix it up slightly. Pretend you are a user making a bespoke configuration on the network device (making a change outside of automation). The state: overridden will circle back on enforcing the data model (configuration policy enforcement) and remove the bespoke change.
If the user wants to re-configure the Cisco IOS device entirely pre-configured ACLs, then resource module overridden state is the most appropriate. When using the overridden state, a user can override all ACLs with user provided ACLs.
To show the difference between replaced and overridden state working, we will be using the same play that we used for the replaced scenario, keeping the pre-existing configuration the same as well.
ACLs configuration:
acls:
- afi: ipv4
acls:
- name: 110
aces:
- grant: deny
sequence: 20
protocol_options:
tcp:
ack: true
source:
address: 198.51.100.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
destination:
address: 198.51.110.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: www
dscp: ef
ttl:
eq: 10
- name: 150
aces:
- grant: deny
sequence: 10
protocol_options:
tcp:
syn: true
source:
address: 198.51.100.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
destination:
address: 198.51.110.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
dscp: ef
ttl:
eq: 10
Ansible Playbook Example
---
- name: Overridden state play
hosts: cisco
gather_facts: false
tasks:
- name: Override ACLs config with device existing ACLs config
cisco.ios.ios_acls:
state: overridden
config: "{{ acls }}"
With the above play, the user is replacing the 123 extended ACL with the provided ACL ACEs configuration and also configuring the 150 extended new ACL ACEs.
Before running the Overridden play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
With Overridden play run, commands that are sent:
- no ip access-list standard std_acl
- no ip access-list extended 110
- no ip access-list extended 123
- no ip access-list extended 150
- no ip access-list extended test
- no ipv6 access-list R1_TRAFFIC
- ip access-list extended 150
- 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
- ip access-list extended 110
- 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
After running the Overridden play network device configuration:
cisco#sh access-lists
Extended IP access list 110
20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
Extended IP access list 150
10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
Now, again if we dig the overridden play output:
- Overridden negates all of the pre-existing ACLs and deletes those configurations, which are not present inside the provided config.
- For the ACL configurations that are pre-existing and also in the play, ios_acls overridden state will try to delete/negate all the pre-existing ACEs and then configure the new ACE as mentioned in the play
- For any non-existing ACLs, overridden state will configure the ACL in a manner same as merged
Now that we talked about how we can configure ACLs and the ACEs on the CISCO IOS device by using ios_acls resource module merged, replaced and overridden state, it’s time we talk about how we can delete the pre-configured ACLs and ACEs and what level of granularity is available with the deleted operational state for the user.
Using state Deleted - Deleting configuration changes
If the user wants to delete the Cisco IOS device pre-configured ACLs with the provided ACL configuration, then use the resource module delete state.
Method 1: Delete individual ACL based on ACL number (which means if the user needs to delete any specific ACLs configured under IPV4 or IPV6).
Ref gist link:
ACLs that need to be deleted
acls:
- afi: ipv4
acls:
- name: test
acl_type: extended
- name: 110
- name: 123
- afi: ipv6
acls:
- name: R1_TRAFFIC
Ansible Playbook Example
---
- name: Deleted state play
hosts: cisco
gather_facts: false
tasks:
- name: Delete ACLs based on ACL number
cisco.ios.ios_acls:
state: deleted
config: "{{ acls }}"
Before running the Deleted play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
With Delete by ACLs Play run, commands that are sent:
- no ip access-list extended test
- no ip access-list extended 110
- no ip access-list extended 123
- no ipv6 access-list R1_TRAFFIC
After running the Deleted play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
cisco#
Method 2: Deleting individual ACL based on it’s AFI (i.e. Address Family Indicator) which means if the user needs to delete all of the ACLs configured under IPV4 or IPV6.
Ansible Playbook Example
---
- name: Deleted state play
hosts: cisco
gather_facts: false
tasks:
- name: Delete ALL IPV4 configured ACLs
cisco.ios.ios_acls:
config:
- afi: ipv4
state: deleted
Before running the Deleted play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
With Delete by ACLs Play run, commands that are fired:
- no ip access-list standard std_acl
- no ip access-list extended test
- no ip access-list extended 110
- no ip access-list extended 123
- no ip access-list extended test
After running the Deleted play network device configuration:
cisco#sh access-lists
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
cisco#
Method 3: Delete ALL ACLs at once
Note: this is a very critical delete operation and if not used judiciously, it has the power of deleting all pre-configured ACLs
Ansible Playbook Example
---
- name: Deleted state play
hosts: cisco
gather_facts: false
tasks:
- name: Delete ALL configured ACLs w/o passing any config
cisco.ios.ios_acls:
state: deleted
Before running the Deleted play network device configuration:
cisco#sh access-lists
Standard IP access list std_acl
10 deny 192.168.1.200
20 deny 192.168.2.0, wildcard bits 0.0.0.255
Extended IP access list 110
10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
Extended IP access list 123
10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
Extended IP access list test
10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
IPv6 access list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11 sequence 10
With Delete by ACLs Play run, commands that are fired:
- no ip access-list standard std_acl
- no ip access-list extended test
- no ip access-list extended 110
- no ip access-list extended 123
- no ip access-list extended test
- no ipv6 access-list R1_TRAFFIC
After running the Overridden play network device configuration:
cisco#sh access-lists
cisco#
Using state rendered - Development and working offline
The state rendered transforms the provided structured data model into platform specific CLI commands. This state does not require a connection to the end device. For this example, it will render the provided data model into the Cisco IOS syntax commands.
Ref gist link: https://gist.githubusercontent.com/justjais/bb2a65c373ab4e64d1eeb47bc425c613/raw/8c65946eae561ff569cfc5398879c51598ae050c/Rendered.txt
ACLs Config that needs to be rendered
acls:
- afi: ipv4
acls:
- name: 110
aces:
- grant: deny
sequence: 10
protocol_options:
tcp:
syn: true
source:
address: 192.0.2.0
wildcard_bits: 0.0.0.255
destination:
address: 192.0.3.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: www
dscp: ef
ttl:
eq: 10
- name: 150
aces:
- grant: deny
protocol_options:
tcp:
syn: true
source:
address: 198.51.100.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
destination:
address: 198.51.110.0
wildcard_bits: 0.0.0.255
port_protocol:
eq: telnet
dscp: ef
ttl:
eq: 10
Ansible Playbook Example
---
- name: Rendered state play
hosts: cisco
gather_facts: false
tasks:
- name: Render the provided configuration
cisco.ios.ios_acls:
config: "{{ acls }}"
state: rendered
With Render state module execution results:
"rendered": [
"ip access-list extended 110",
"10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10",
"ip access-list extended 150",
"deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10"
]
NOTE: Render state won’t change anything from configuration end
Using state parsed - Development and working offline
This state reads the configuration from running_config option and transforms it into structured data (i.e. JSON). This is helpful if you have off-line configurations, such as a backup text file, and want to transform it into structured data. This is helpful for experimenting, troubleshooting or offline creation of a source of truth for your data models.
Ref gist link: https://gist.githubusercontent.com/justjais/bb2a65c373ab4e64d1eeb47bc425c613/raw/8c65946eae561ff569cfc5398879c51598ae050c/Parsed.txt
ACLs Config that needs to be Parsed
Ansible Playbook Example
---
- name: Parsed state play
hosts: cisco
gather_facts: false
tasks:
- name: Parse the provided ACLs configuration
cisco.ios.ios_acls:
running_config:
"ipv6 access-list R1_TRAFFIC
deny tcp any eq www any eq telnet ack dscp af11"
state: parsed
With Parsed state module execution results:
"parsed": [
{
"acls": [
{
"aces": [
{
"destination": {
"any": true,
"port_protocol": {
"eq": "telnet"
}
},
"dscp": "af11",
"grant": "deny",
"protocol_options": {
"tcp": {
"ack": true
}
},
"source": {
"any": true,
"port_protocol": {
"eq": "www"
}
}
}
],
"name": "R1_TRAFFIC"
}
],
"afi": "ipv6"
}
]
Conclusion
The ACLs resource modules provide an easy way for network engineers to begin automating access lists on multiple network platforms. While some configuration can remain static on network devices, ACLs might need constant updates and verification. These resource modules allow users to adopt automation in incremental steps to make it easy for organizations to adopt. As soon as you have transformed your ACLs into structured data, any resource module from any network platform can read. Imagine reading in ACLs for your Cisco IOS box and transforming them into Cisco IOS-XR commands.
Do you want to meet the blog authors? Come attend virtual AnsibleFest 2020! We have an entire track dedicated to Ansible Network Automation. Did we mention it is free? Sign up here.
Are you new to Ansible Network Automation? Check out our Getting Started Page!
Do you want some free training? Check out Ansible Automation Technical Workshops.
Or just come chat with us on Slack.