This is the completed Security Audit playbook.
The playbook goes through a basic approved configuration for the devices. If there is anything missing, it is added. If there is anything that should not be there such as; an extra ACL line, or an extra NTP server or the enable secret being different this is fixed.
The idea of this playbook is that it can be run against the devices as part of a cron job. This way, any malicious or misconfiguration can be fixed easily and automatically.
I have a basic approved configuration that covers my devices. If we need additional individual commands they can be added in the host_vars files that devices have, more about that can be read here.
The playbook can be found in my GitHub
snmp-server community COM_STRING RO
logging host 130.130.130.101
enable secret 5 $1$1kIy$42yUvkQHylbvbNnDv.rjZ/ !(cisco)
ip domain name scrap.lab
ntp server 1.1.1.1
ntp server 2.2.2.2
ip name-server 3.3.3.3
ip name-server 4.4.4.4
ip access-list standard 99
10 permit host 10.1.1.1
20 permit 172.18.0.12 0.0.0.0
30 permit 10.0.0.0 0.255.255.255
40 permit 172.16.1.0 0.0.0.255
200 deny 192.168.0.0 0.0.255.255
210 deny any
line vty 0 4
privilege level 15
password Stefan2020
transport input ssh
access-class 99 in

Differences Between Versions
In the lab I have 5 devices. I have noticed some difference between them when running the playbook. They are minor differences that you would not notice unless comparing. The commands “ip domain name scrap.lab” and “ip domain-name scrap.lab” work the same. However, depending on the device/version, the hyphen between domain and name may not be there.
This causes Ansible to mark the task as changed. When really nothing has actually changed.
SW2: 172.16.1.102
SW3: 172.16.1.103
SW4: 172.16.1.124
R1: 172.16.1.104
R4: 172.16.1.125
In the play recap, nothing has actually changed, but Ansible registers the changes due to slight command differences per devices.
PLAY RECAP **************************************************************************************************************************************************************************
172.16.1.102 : ok=22 changed=4 unreachable=0 failed=0 skipped=12 rescued=0 ignored=0
172.16.1.103 : ok=20 changed=3 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.104 : ok=20 changed=2 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.124 : ok=20 changed=3 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.125 : ok=22 changed=3 unreachable=0 failed=0 skipped=12 rescued=0 ignored=0
Security Audit Playbook
The playbook contains nine plays, there are multiple tasks, some have debug output or return running config.
1. SNMP
2. Logging Host
3. VTY Lines
4. Secret Password
5. Domain Name
6. NTP Servers
7. DNS Servers
8. VTY ACL
9. VTY ACL Applied to VTY Lines
---
#### SNMP ####
- name: SNMP PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
snmp_string: snmp-server community COM_STRING RO
tasks:
- name: Show SNMP
ios_command:
commands:
- "show snmp"
register: pre_snmp_output
# Do not run if SNMP is not Configured
- name: Show Running SNMP
when: pre_snmp_output is not search("%SNMP agent not enabled")
ios_command:
commands:
- "show run | i snmp"
register: misconfigured_SNMP
- name: Configure SNMP
ios_config:
lines:
- "{{ snmp_string }}"
when: pre_snmp_output is search("%SNMP agent not enabled")
register: snmp_changed
# Will remove SNMP config as a list, except if it is the defined SNMP string
- name: Remove Misconfigured SNMP
when:
- misconfigured_SNMP.stdout_lines is defined
- item != "{{ snmp_string }}"
- item != "{{ snmp_location }}"
ios_config:
lines:
- "no {{ item }}"
with_items:
- "{{ misconfigured_SNMP.stdout_lines[0] }}"
register: snmp_misconfigure_fix
- name: SNMP Location
ios_config:
lines:
- "{{ snmp_location }}"
register: post_snmp_output
- name: Show Fixed SNMP Config
ios_command:
commands:
- "show run | i snmp"
when: snmp_misconfigure_fix.changed
register: post_snmp_output
- name: New SNMP
debug:
var: post_snmp_output.stdout_lines[0][0]
when: post_snmp_output.stdout_lines is defined
#### Logging ####
- name: LOGGING HOST PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
logging_host: logging host 130.130.130.101
#### Logging ####
tasks:
- name: Show Run Logging
ios_command:
commands:
- "sh run | i logging"
register: pre_logging_output
- name: Current Logging
debug:
var: pre_logging_output.stdout_lines[0]
when: pre_logging_output.stdout_lines is defined
# Will remove SNMP config as a list, except if it is the defined SNMP string
- name: Remove Logging
ios_config:
lines:
- "no {{ item }}"
with_items:
- "{{ pre_logging_output.stdout_lines[0] }}"
when:
- pre_logging_output.stdout_lines is defined
- '"130.130.130.101" not in item'
- '"synchronous" not in item'
- '"console" not in item'
- '"buffered" not in item'
register: logging_misconfigure_fix
# Always run this, will not change config if already applied
# Some devices can be "logging [IP]" and not "logging host [IP]" as Ansible excpects
- name: Configure Logging
ios_config:
lines:
- "{{ logging_host }}"
register: logging_changed
- name: Show Fixed Logging Config
ios_command:
commands:
- "show run | i logging"
when: (logging_misconfigure_fix.changed or logging_changed.changed)
register: post_logging_output
- name: New Logging
debug:
var: post_logging_output.stdout_lines[0]
when: post_logging_output.stdout_lines is defined
#### VTY Lines ####
- name: VTY PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
vty_config:
- privilege level 15
- password Stefan2020
- transport input ssh
- access-class 99 in
vty_config_ignore:
- "!"
- end
- line vty 0 4
- line vty 5 15
- line vty 0 15
- ntp server 1.1.1.1
- ntp server 2.2.2.2
tasks:
- name: show VTY
ios_command:
commands:
- "show run | b line vty"
register: pre_vty_output
# Configure Correct VTY Config
# Only configure VTY if the vty_config is not in the pre_vty_output
- name: Configure VTY
ios_config:
lines:
- "{{ item }}"
parents: line vty 0 4
loop: "{{ vty_config }}"
when: 'item not in "{{ pre_vty_output.stdout_lines[0]|list }}"'
register: vty_changed
# If show output line is in confg or in config_ignore, skip
# If show output line is not in config or not in config_ignore, remove
# Remove unwated VTY Config
- name: Remove Unwanted VTY Config VTY
ios_config:
lines:
- "no {{ item | trim }}"
parents: line vty 0 4
loop: "{{ pre_vty_output.stdout_lines[0] }}"
when:
- item | trim not in {{ vty_config }}
- item | trim not in {{ vty_config_ignore }}
register: vty_fixed
- name: Show Fixed VTY Config
ios_command:
commands:
- "show run | b line vty"
when:
- vty_changed.changed or vty_fixed.changed
register: post_vty_output
- name: New VTY
debug:
var: post_vty_output.stdout_lines[0]
when: post_vty_output.stdout_lines is defined
#### Secret Lines ####
- name: SECRET PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
enable_secret: enable secret 5 $1$1kIy$42yUvkQHylbvbNnDv.rjZ/
tasks:
- name: Show Secret
ios_command:
commands:
- "show run | i enable secret"
register: pre_secret_output
- name: Show Enable
ios_command:
commands:
- "show run | i enable password"
register: pre_enable_output
- debug:
var: "pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')"
- name: Remove Enable Password
loop: "{{ pre_enable_output.stdout_lines[0] }}"
when:
- '"enable password" in pre_enable_output.stdout_lines | trim'
# - item is not search("{{ vty_config|list }}")
# - item == "privilege level 15"
ios_config:
lines:
- no {{ item.split()[:-1] | join(' ') }}
register: enable_misconfigure_fix
# NEED TO DO THE SAME WITH SECRET PASSWORD, -2 FOR THAT TO REMOVE HASH AND 5
- debug:
var: "pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')"
- name: Configure secret Password
ios_config:
lines:
- "{{ enable_secret }}"
register: config_secret
#### Domain Name ####
- name: DOMAIN PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
domain: ip domain name scrap.lab
tasks:
- name: Configure Domain
ios_config:
lines:
- "{{ domain }}"
register: config_domain
#### NTP ####
- name: NTP PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
ntp_config:
- ntp server 1.1.1.1
- ntp server 2.2.2.2
tasks:
- name: Show NTP
ios_command:
commands:
- "show run | i ntp"
register: pre_ntp_output
- debug:
var: "pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')"
- name: Remove Unwanted NTP Config
ios_config:
lines:
- "no {{ item | trim }}"
loop: "{{ pre_ntp_output.stdout_lines[0] }}"
when:
- item | trim not in {{ ntp_config }}
- item != "" # When equal to empty string, skip
register: ntp_fixed
- name: configure NTP
ios_config:
lines:
- "{{ item }}"
with_items:
- "{{ ntp_config }}"
register: ntp_changed
#### DNS ####
- name: DNS PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
vars:
dns_config:
- ip name-server 3.3.3.3
- ip name-server 4.4.4.4
tasks:
- name: Show DNS
ios_command:
commands:
- "show run | i name-server"
register: pre_dns_output
- name: Remove Unwanted DNS Config
ios_config:
lines:
- "no {{ item | trim }}"
loop: "{{ pre_dns_output.stdout_lines[0] }}"
when:
- item | trim not in {{ dns_config }}
- item != "" # When equal to empty string, skip
register: dns_fixed
- name: Configure DNS
ios_config:
lines:
- "{{ item }}"
with_items:
- "{{ dns_config }}"
register: ntp_changed
#### VTY ACL ####
# https://www.ansible.com/blog/deep-dive-acl-configuration-management-using-ansible-network-automation-resource-modules
- name: VTY ACL - REPLACED STATE PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
tasks:
- name: Replace ACLs config with device existing ACLs config
ios_acls:
state: replaced
config: "{{ acls }}"
#### VTY ACL Lines ####
- name: VTY ACL PLAY
hosts: all_devices
gather_facts: false
connection: network_cli
tasks:
# Configure Correct VTY Config
# Only configure VTY if the vty_config is not in the pre_vty_output
- name: Configure VTY
ios_config:
lines:
- access-class 99 in
parents: line vty 0 4
Running Security Audit Playbook
For the demonstration of the playbook. I have the three switches without any of the security configuration applied. R1 has incorrect configuration applied and R4 has the correct configuration applied.

R1 Misconfiguration, these lines have been added to R1. They will all be removed from R1 by the Ansible playbook and corrected.
ip access-list standard 10
10 permit host 10.1.1.1
20 permit 172.18.0.12 0.0.0.0
snmp-server community WRONG_WRONG1 RO
snmp-server community WRONG_WRONG2 RO
snmp-server community WRONG_WRONG3 RO
snmp-server community WRONG_WRONG4 RO
logging host 1.1.1.1
logging host 2.2.2.2
logging host 1.1.1.2
logging host 1.1.1.3
logging host 1.1.1.4
logging host 1.1.1.5
logging host 1.1.1.6
logging host 1.1.1.7
logging host 1.1.1.8
logging host 1.1.1.9The result of the playbook sees the switches and the router have the most changes. R4 (172.16.1.125 has the least changes. Just a logging host command, one that is slightly different to what the IOS module is expecting, and the replaced ACL 99.
The plays are removing the misconfigured commands on the R1, these can be seen in the playbook output below. The incorrect SNMP strings are removed, for example.
stef@stef-VirtualBox:~/Ansible_projects$ ansible-playbook -c paramiko playbooks/pb4_securityaudit112_complete.yml --ask-vault-pass
Vault password:
PLAY [SNMP PLAY] ********************************************************************************************************************************************************************
TASK [Show SNMP] ********************************************************************************************************************************************************************
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Show Running SNMP] ************************************************************************************************************************************************************
skipping: [172.16.1.102]
skipping: [172.16.1.103]
skipping: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Configure SNMP] ***************************************************************************************************************************************************************
skipping: [172.16.1.104]
skipping: [172.16.1.125]
changed: [172.16.1.124]
changed: [172.16.1.102]
changed: [172.16.1.103]
TASK [Remove Misconfigured SNMP] ****************************************************************************************************************************************************
skipping: [172.16.1.102]
skipping: [172.16.1.124]
skipping: [172.16.1.103]
skipping: [172.16.1.125] => (item=snmp-server community COM_STRING RO)
skipping: [172.16.1.125] => (item=snmp-server location PARIS)
changed: [172.16.1.104] => (item=snmp-server community WRONG_WRONG1 RO)
changed: [172.16.1.104] => (item=snmp-server community WRONG_WRONG2 RO)
changed: [172.16.1.104] => (item=snmp-server community WRONG_WRONG3 RO)
changed: [172.16.1.104] => (item=snmp-server community WRONG_WRONG4 RO)
TASK [SNMP Location] ****************************************************************************************************************************************************************
changed: [172.16.1.102]
changed: [172.16.1.124]
changed: [172.16.1.103]
ok: [172.16.1.125]
changed: [172.16.1.104]
TASK [Show Fixed SNMP Config] *******************************************************************************************************************************************************
skipping: [172.16.1.102]
skipping: [172.16.1.124]
skipping: [172.16.1.103]
skipping: [172.16.1.125]
ok: [172.16.1.104]
TASK [New SNMP] *********************************************************************************************************************************************************************
skipping: [172.16.1.102]
skipping: [172.16.1.103]
skipping: [172.16.1.124]
skipping: [172.16.1.125]
ok: [172.16.1.104] => {
"post_snmp_output.stdout_lines[0][0]": "snmp-server location LONDON"
}
PLAY [LOGGING HOST PLAY] ************************************************************************************************************************************************************
TASK [Show Run Logging] *************************************************************************************************************************************************************
ok: [172.16.1.103]
ok: [172.16.1.102]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Current Logging] **************************************************************************************************************************************************************
ok: [172.16.1.104] => {
"pre_logging_output.stdout_lines[0]": [
"no logging console",
"logging host 1.1.1.1",
"logging host 2.2.2.2",
"logging host 1.1.1.2",
"logging host 1.1.1.3",
"logging host 1.1.1.4",
"logging host 1.1.1.5",
"logging host 1.1.1.6",
"logging host 1.1.1.7",
"logging host 1.1.1.8",
"logging host 1.1.1.9",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.102] => {
"pre_logging_output.stdout_lines[0]": [
"logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL ",
"logging buffered 50000",
"no logging console",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.125] => {
"pre_logging_output.stdout_lines[0]": [
"logging 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.124] => {
"pre_logging_output.stdout_lines[0]": [
"logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL ",
"logging buffered 50000",
"no logging console",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.103] => {
"pre_logging_output.stdout_lines[0]": [
"logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL ",
"logging buffered 50000",
"no logging console",
" logging synchronous",
" logging synchronous"
]
}
TASK [Remove Logging] ***************************************************************************************************************************************************************
skipping: [172.16.1.104] => (item=no logging console)
skipping: [172.16.1.125] => (item=logging 130.130.130.101)
skipping: [172.16.1.125] => (item= logging synchronous)
skipping: [172.16.1.125] => (item= logging synchronous)
changed: [172.16.1.103] => (item=logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL )
skipping: [172.16.1.103] => (item=logging buffered 50000)
skipping: [172.16.1.103] => (item=no logging console)
skipping: [172.16.1.103] => (item= logging synchronous)
skipping: [172.16.1.103] => (item= logging synchronous)
changed: [172.16.1.102] => (item=logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL )
skipping: [172.16.1.102] => (item=logging buffered 50000)
skipping: [172.16.1.102] => (item=no logging console)
skipping: [172.16.1.102] => (item= logging synchronous)
skipping: [172.16.1.102] => (item= logging synchronous)
changed: [172.16.1.124] => (item=logging discriminator EXCESS severity drops 6 msg-body drops EXCESSCOLL )
skipping: [172.16.1.124] => (item=logging buffered 50000)
skipping: [172.16.1.124] => (item=no logging console)
skipping: [172.16.1.124] => (item= logging synchronous)
skipping: [172.16.1.124] => (item= logging synchronous)
changed: [172.16.1.104] => (item=logging host 1.1.1.1)
changed: [172.16.1.104] => (item=logging host 2.2.2.2)
changed: [172.16.1.104] => (item=logging host 1.1.1.2)
changed: [172.16.1.104] => (item=logging host 1.1.1.3)
changed: [172.16.1.104] => (item=logging host 1.1.1.4)
changed: [172.16.1.104] => (item=logging host 1.1.1.5)
changed: [172.16.1.104] => (item=logging host 1.1.1.6)
changed: [172.16.1.104] => (item=logging host 1.1.1.7)
changed: [172.16.1.104] => (item=logging host 1.1.1.8)
changed: [172.16.1.104] => (item=logging host 1.1.1.9)
skipping: [172.16.1.104] => (item= logging synchronous)
skipping: [172.16.1.104] => (item= logging synchronous)
TASK [Configure Logging] ************************************************************************************************************************************************************
changed: [172.16.1.103]
changed: [172.16.1.102]
changed: [172.16.1.124]
changed: [172.16.1.104]
changed: [172.16.1.125]
TASK [Show Fixed Logging Config] ****************************************************************************************************************************************************
ok: [172.16.1.103]
ok: [172.16.1.102]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [New Logging] ******************************************************************************************************************************************************************
ok: [172.16.1.104] => {
"post_logging_output.stdout_lines[0]": [
"no logging console",
"logging host 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.103] => {
"post_logging_output.stdout_lines[0]": [
"logging buffered 50000",
"no logging console",
"logging host 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.124] => {
"post_logging_output.stdout_lines[0]": [
"logging buffered 50000",
"no logging console",
"logging host 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.125] => {
"post_logging_output.stdout_lines[0]": [
"logging 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
ok: [172.16.1.102] => {
"post_logging_output.stdout_lines[0]": [
"logging buffered 50000",
"no logging console",
"logging 130.130.130.101",
" logging synchronous",
" logging synchronous"
]
}
PLAY [VTY PLAY] *********************************************************************************************************************************************************************
TASK [show VTY] *********************************************************************************************************************************************************************
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Configure VTY] ****************************************************************************************************************************************************************
skipping: [172.16.1.104] => (item=privilege level 15)
skipping: [172.16.1.104] => (item=password Stefan2020)
skipping: [172.16.1.104] => (item=transport input ssh)
skipping: [172.16.1.102] => (item=privilege level 15)
skipping: [172.16.1.102] => (item=password Stefan2020)
skipping: [172.16.1.102] => (item=transport input ssh)
skipping: [172.16.1.103] => (item=privilege level 15)
skipping: [172.16.1.103] => (item=password Stefan2020)
skipping: [172.16.1.103] => (item=transport input ssh)
skipping: [172.16.1.124] => (item=privilege level 15)
skipping: [172.16.1.124] => (item=password Stefan2020)
skipping: [172.16.1.124] => (item=transport input ssh)
skipping: [172.16.1.125] => (item=privilege level 15)
skipping: [172.16.1.125] => (item=password Stefan2020)
skipping: [172.16.1.125] => (item=transport input ssh)
skipping: [172.16.1.125] => (item=access-class 99 in)
changed: [172.16.1.102] => (item=access-class 99 in)
changed: [172.16.1.124] => (item=access-class 99 in)
changed: [172.16.1.103] => (item=access-class 99 in)
changed: [172.16.1.104] => (item=access-class 99 in)
TASK [Remove Unwanted VTY Config VTY] ***********************************************************************************************************************************************
skipping: [172.16.1.104] => (item=line vty 0 4)
skipping: [172.16.1.104] => (item= privilege level 15)
skipping: [172.16.1.104] => (item= password Stefan2020)
skipping: [172.16.1.104] => (item= transport input ssh)
skipping: [172.16.1.102] => (item=line vty 0 4)
skipping: [172.16.1.102] => (item= privilege level 15)
skipping: [172.16.1.104] => (item=!)
skipping: [172.16.1.102] => (item= password Stefan2020)
skipping: [172.16.1.102] => (item= transport input ssh)
skipping: [172.16.1.104] => (item=!)
skipping: [172.16.1.102] => (item=!)
skipping: [172.16.1.104] => (item=end)
skipping: [172.16.1.102] => (item=end)
skipping: [172.16.1.103] => (item=line vty 0 4)
skipping: [172.16.1.103] => (item= privilege level 15)
skipping: [172.16.1.103] => (item= password Stefan2020)
skipping: [172.16.1.103] => (item= transport input ssh)
skipping: [172.16.1.103] => (item=!)
skipping: [172.16.1.124] => (item=line vty 0 4)
skipping: [172.16.1.103] => (item=end)
skipping: [172.16.1.124] => (item= privilege level 15)
skipping: [172.16.1.124] => (item= password Stefan2020)
skipping: [172.16.1.125] => (item=line vty 0 4)
skipping: [172.16.1.124] => (item= transport input ssh)
skipping: [172.16.1.125] => (item= access-class 99 in)
skipping: [172.16.1.125] => (item= privilege level 15)
skipping: [172.16.1.125] => (item= password Stefan2020)
skipping: [172.16.1.124] => (item=!)
skipping: [172.16.1.124] => (item=end)
skipping: [172.16.1.125] => (item= transport input ssh)
skipping: [172.16.1.125] => (item=line vty 5 15)
skipping: [172.16.1.125] => (item= privilege level 15)
skipping: [172.16.1.125] => (item= password Stefan2020)
skipping: [172.16.1.125] => (item= transport input ssh)
skipping: [172.16.1.125] => (item=!)
skipping: [172.16.1.125] => (item=ntp server 1.1.1.1)
skipping: [172.16.1.125] => (item=ntp server 2.2.2.2)
skipping: [172.16.1.125] => (item=!)
skipping: [172.16.1.125] => (item=end)
TASK [Show Fixed VTY Config] ********************************************************************************************************************************************************
skipping: [172.16.1.125]
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
TASK [New VTY] **********************************************************************************************************************************************************************
skipping: [172.16.1.125]
ok: [172.16.1.104] => {
"post_vty_output.stdout_lines[0]": [
"line vty 0 4",
" access-class 99 in",
" privilege level 15",
" password Stefan2020",
" transport input ssh",
"!",
"!",
"end"
]
}
ok: [172.16.1.102] => {
"post_vty_output.stdout_lines[0]": [
"line vty 0 4",
" access-class 99 in",
" privilege level 15",
" password Stefan2020",
" transport input ssh",
"!",
"end"
]
}
ok: [172.16.1.103] => {
"post_vty_output.stdout_lines[0]": [
"line vty 0 4",
" access-class 99 in",
" privilege level 15",
" password Stefan2020",
" transport input ssh",
"!",
"end"
]
}
ok: [172.16.1.124] => {
"post_vty_output.stdout_lines[0]": [
"line vty 0 4",
" access-class 99 in",
" privilege level 15",
" password Stefan2020",
" transport input ssh",
"!",
"end"
]
}
PLAY [SECRET PLAY] ******************************************************************************************************************************************************************
TASK [Show Secret] ******************************************************************************************************************************************************************
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Show Enable] ******************************************************************************************************************************************************************
ok: [172.16.1.124]
ok: [172.16.1.103]
ok: [172.16.1.102]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [debug] ************************************************************************************************************************************************************************
ok: [172.16.1.102] => {
"pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.103] => {
"pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.125] => {
"pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.124] => {
"pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.104] => {
"pre_enable_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
TASK [Remove Enable Password] *******************************************************************************************************************************************************
skipping: [172.16.1.104] => (item=)
skipping: [172.16.1.102] => (item=)
skipping: [172.16.1.103] => (item=)
skipping: [172.16.1.124] => (item=)
skipping: [172.16.1.125] => (item=)
TASK [debug] ************************************************************************************************************************************************************************
ok: [172.16.1.104] => {
"pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')": "enable secret"
}
ok: [172.16.1.124] => {
"pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')": ""
}
ok: [172.16.1.102] => {
"pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')": "enable secret"
}
ok: [172.16.1.103] => {
"pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')": "enable secret"
}
ok: [172.16.1.125] => {
"pre_secret_output.stdout_lines[0][0].split()[:-2] | join(' ')": "enable secret"
}
TASK [Configure secret Password] ****************************************************************************************************************************************************
changed: [172.16.1.102]
changed: [172.16.1.103]
changed: [172.16.1.124]
ok: [172.16.1.125]
changed: [172.16.1.104]
PLAY [DOMAIN PLAY] ******************************************************************************************************************************************************************
TASK [Configure Domain] *************************************************************************************************************************************************************
changed: [172.16.1.102]
changed: [172.16.1.103]
ok: [172.16.1.104]
changed: [172.16.1.124]
ok: [172.16.1.125]
PLAY [NTP PLAY] *********************************************************************************************************************************************************************
TASK [Show NTP] *********************************************************************************************************************************************************************
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.102]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [debug] ************************************************************************************************************************************************************************
ok: [172.16.1.124] => {
"pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.125] => {
"pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')": "ntp server"
}
ok: [172.16.1.103] => {
"pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.102] => {
"pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
ok: [172.16.1.104] => {
"pre_ntp_output.stdout_lines[0][0].split()[:-1] | join(' ')": ""
}
TASK [Remove Unwanted NTP Config] ***************************************************************************************************************************************************
skipping: [172.16.1.104] => (item=)
skipping: [172.16.1.102] => (item=)
skipping: [172.16.1.103] => (item=)
skipping: [172.16.1.124] => (item=)
skipping: [172.16.1.125] => (item=ntp server 1.1.1.1)
skipping: [172.16.1.125] => (item=ntp server 2.2.2.2)
TASK [configure NTP] ****************************************************************************************************************************************************************
changed: [172.16.1.102] => (item=ntp server 1.1.1.1)
changed: [172.16.1.124] => (item=ntp server 1.1.1.1)
changed: [172.16.1.103] => (item=ntp server 1.1.1.1)
changed: [172.16.1.104] => (item=ntp server 1.1.1.1)
ok: [172.16.1.125] => (item=ntp server 1.1.1.1)
changed: [172.16.1.102] => (item=ntp server 2.2.2.2)
ok: [172.16.1.125] => (item=ntp server 2.2.2.2)
changed: [172.16.1.124] => (item=ntp server 2.2.2.2)
changed: [172.16.1.103] => (item=ntp server 2.2.2.2)
changed: [172.16.1.104] => (item=ntp server 2.2.2.2)
PLAY [DNS PLAY] *********************************************************************************************************************************************************************
TASK [Show DNS] *********************************************************************************************************************************************************************
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
TASK [Remove Unwanted DNS Config] ***************************************************************************************************************************************************
skipping: [172.16.1.104] => (item=)
skipping: [172.16.1.102] => (item=)
skipping: [172.16.1.103] => (item=)
skipping: [172.16.1.124] => (item=)
skipping: [172.16.1.125] => (item=ip name-server 3.3.3.3)
skipping: [172.16.1.125] => (item=ip name-server 4.4.4.4)
TASK [Configure DNS] ****************************************************************************************************************************************************************
changed: [172.16.1.102] => (item=ip name-server 3.3.3.3)
changed: [172.16.1.124] => (item=ip name-server 3.3.3.3)
changed: [172.16.1.103] => (item=ip name-server 3.3.3.3)
ok: [172.16.1.125] => (item=ip name-server 3.3.3.3)
changed: [172.16.1.104] => (item=ip name-server 3.3.3.3)
ok: [172.16.1.125] => (item=ip name-server 4.4.4.4)
changed: [172.16.1.124] => (item=ip name-server 4.4.4.4)
changed: [172.16.1.102] => (item=ip name-server 4.4.4.4)
changed: [172.16.1.103] => (item=ip name-server 4.4.4.4)
changed: [172.16.1.104] => (item=ip name-server 4.4.4.4)
PLAY [VTY ACL - REPLACED STATE PLAY] ************************************************************************************************************************************************
TASK [Replace ACLs config with device existing ACLs config] *************************************************************************************************************************
changed: [172.16.1.103]
changed: [172.16.1.102]
changed: [172.16.1.124]
changed: [172.16.1.104]
changed: [172.16.1.125]
PLAY [VTY ACL PLAY] *****************************************************************************************************************************************************************
TASK [Configure VTY] ****************************************************************************************************************************************************************
ok: [172.16.1.102]
ok: [172.16.1.103]
ok: [172.16.1.124]
ok: [172.16.1.104]
ok: [172.16.1.125]
PLAY RECAP **************************************************************************************************************************************************************************
172.16.1.102 : ok=26 changed=10 unreachable=0 failed=0 skipped=8 rescued=0 ignored=0
172.16.1.103 : ok=26 changed=10 unreachable=0 failed=0 skipped=8 rescued=0 ignored=0
172.16.1.104 : ok=29 changed=9 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
172.16.1.124 : ok=26 changed=10 unreachable=0 failed=0 skipped=8 rescued=0 ignored=0
172.16.1.125 : ok=22 changed=2 unreachable=0 failed=0 skipped=12 rescued=0 ignored=0 Rerunning the playbook on the same devices results in fewer changes. But still changes as there are command variations that the IOS module does not take into account.
PLAY RECAP **************************************************************************************************************************************************************************
172.16.1.102 : ok=25 changed=4 unreachable=0 failed=0 skipped=9 rescued=0 ignored=0
172.16.1.103 : ok=20 changed=2 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.104 : ok=20 changed=1 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.124 : ok=20 changed=2 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
172.16.1.125 : ok=22 changed=2 unreachable=0 failed=0 skipped=12 rescued=0 ignored=0 