Ansible Project: Network Security Audit 5 – Complete Security Audit Playbook

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.9

The 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 

Leave a Comment

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