As I have been going through my list of configuration items for the security audit, I have only used Ansible to send commands. I haven’t used the ios_config module for any of its other abilities like interface configuration, gathering facts or ACL configuration. This post will cover 2/3 of those. Gathering facts, specifically ACL facts and ACL configuration.
A great resource I used for this post can be found on the Ansible website blog. It covers more of the ACL configuration differences that can be performed. I did run into a couple of issues, so I’ll note them down.
The playbooks I will use here can be found on my GitHub.
Gathering ACL Configuration and Creating ACL Host Vars
The gathering of the current ACLs and saving them as host_vars is important. The ios_acls module creates the ACLs in a specific format that would be time-consuming and frustrating to manually create.
Current ACL. Very basic standard ACL.
0
1
2
3
4
5
6
7
8
ip access-list standard99
10permit host10.1.1.1
20permit172.18.0.120.0.0.0
30permit10.0.0.00.255.255.255
40permit172.16.1.00.0.0.255
200deny192.168.0.00.0.255.255
210deny any
Ansible will need a variable that looks like the below. This is readable, if you compare to the Cisco config above. It’s very long and not easily readable. Nobody wants to manually create this.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
acls:
-acls:
-aces:
-grant:permit
sequence:10
source:
host:10.1.1.1
-grant:permit
sequence:20
source:
host:172.18.0.12
-grant:permit
sequence:30
source:
address:10.0.0.0
wildcard_bits:0.255.255.255
-grant:permit
sequence:40
source:
address:172.16.1.0
wildcard_bits:0.0.0.255
-grant:deny
sequence:200
source:
address:192.168.0.0
wildcard_bits:0.0.255.255
-grant:deny
sequence:210
source:
address:any# modified from host as it casues an error
acl_type:standard
name:'99'
afi:ipv4
To avoid manually creating the ios_acl module can do it and save it in the correct location for host_vars. Although I am going to use this as a group_var, so I will just manually copy the yaml over.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
-name:convert configured ACLs tostructured data
hosts:lab_core
gather_facts:false
connection:network_cli
tasks:
-name:Usethe ACLs resource module togather the current config
I did have an issue with the resulting host_var files. The last line of my ACL is a deny any.
0
1
2
3
4
5
ip access-list standard99
10permit host10.1.1.1
...
210deny any
The deny any line on 210 is similar to the host line on 10. The ios_acl has interpreted the “any” as a hostname. This causes an error when the ACL is run as the command “210 deny host any” is sent to the device, resulting in an error.
PLAY[VTY ACL-Replaced state play]*********************************************************************************************************************************************
TASK[Replace ACLs config with device existing ACLs config]**********************************************************************************************************************
[WARNING]:ansible-pylibssh notinstalled,falling back toparamiko
[WARNING]:ansible-pylibssh notinstalled,falling back toparamiko
fatal:[172.16.1.104]:FAILED!=>{
"changed":false
}
MSG:
MODULE FAILURE
See stdout/stderr forthe exact error
MODULE_STDERR:
210deny host any
Translating"any"
Translating"host"
210denyhostany
^
%Invalidinputdetectedat'^'marker.
R1(config-std-nacl)#
ok:[172.16.1.125]
PLAY RECAP ***********************************************************************************************************************************************************************
To fix this I simply opened the yaml file where the ACL variable is and changed the key of “host” for “address”. This worked, and the ACL can be applied successfully.
This does cause problems with the ability for Ansible to compare the ACL that is gathered from the device and to what the group_var has. They will always be different due to ios_acl incorrectly assuming that “any” is a host. The only solution to this is to remove the explicit deny statement from the ACL.
Configuring Devices With ACLs
Now that the ACL in yaml format has been added to the group_vars file (below). The next step is to create a playbook that can use this to make changes.
address:any# modified from host as it casues an error
acl_type:standard
name:'99'
afi:ipv4
The ACL configuration playbook will utilise the ios_acl module, and therefore it’s very easy to configure as the complex checking is handled by the module. For this configuration, I have chosen to use the “replaced” state for the ACL configuration. This means that the ios_acl will remove the ACLs referenced in the group_vars file before applying the correct ACLs.
In my example case, there is only a single ACL in the group_vars, ACL 99. So if there were another ACL, say ACL 10 on the device, this one would not be touched, it will remain as last configured.
The below playbook will simply remove entries in ACL 99 and then apply the entries from the group_vars file. This task will always show as changing the configuration. There is no comparison taking place to check if it is required.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
-name:VTY ACL-Replaced state play
hosts:lab_core
gather_facts:false
connection:network_cli
tasks:
-name:Replace ACLs config with device existing ACLs config
PLAY[VTY ACL-Replaced state play]*********************************************************************************************************************************************
TASK[Usethe ACLs resource module togather the current config]*****************************************************************************************************************
[WARNING]:ansible-pylibssh notinstalled,falling back toparamiko
[WARNING]:ansible-pylibssh notinstalled,falling back toparamiko
ok:[172.16.1.104]
ok:[172.16.1.125]
TASK[Replace ACLs config with device existing ACLs config]**********************************************************************************************************************
changed:[172.16.1.104]
changed:[172.16.1.125]
PLAY RECAP ***********************************************************************************************************************************************************************
The ACL 10 is still present after the change. As this is not in the group_vars file, it is not modified by Ansible.
0
1
2
3
4
5
6
7
8
9
10
11
12
R1(config-std-nacl)#do sh ip access-lists
Standard IP access list10
10permit10.1.1.1
20permit172.18.0.12
Standard IP access list99
10permit10.1.1.1
20permit172.18.0.12
30permit10.0.0.0,wildcard bits0.255.255.255
40permit172.16.1.0,wildcard bits0.0.0.255
200deny192.168.0.0,wildcard bits0.0.255.255
210deny any
Configuring ACL 99 on VTY Lines
I have left the configuration of the VTY lines to the very last step. I had hoped to perform a comparison of the ACL 99 applied on the device with what is in the group_var. However, they do not match, due to my workaround and also because they are named differently. A comparison using “show run” commands is probably easier.