Back to .md Directory

NTP Compliance

An Ansible playbook that audits NTP server configurations on Cisco IOS and IOS XR devices, then uploads a compliance report to S3.

May 2, 2026
0 downloads
0 views
View source

What this file does

An Ansible playbook that audits NTP server configurations on Cisco IOS and IOS XR devices, then uploads a compliance report to S3.

When to use it

  • Auditing NTP server settings across a fleet of Cisco network devices
  • Automating NTP compliance reporting with an S3-hosted HTML report
  • Enforcing a desired set of NTP servers and removing non-compliant entries
  • Integrating NTP compliance checks into a CI/CD pipeline for network changes

Assumes this stack

Ansibleboto3AWS S3Cisco IOSCisco IOS XR

NTP Compliance

Pre-requisites

The boto package is required.

sudo pip3 install boto3

You need AWS credentials to create a Compliance report on S3. You need to export AWS_ACCESS_KEY and AWS_SECRET_KEY before executing.

Variables required

  • my_devices: One or more groups or host patterns, separated by colons.
  • my_facts: Whether to collect facts per device: yes or no.
  • my_bucket: S3 bucket where to host the report. Ex mydemo.run.
  • my_ntp_servers: List of NTP server IP addresses.

Playbook

Latest version -> ios-genie-show-ver. The following output might be outdated.

  hosts: "{{ my_devices }}"
  gather_facts: "{{ my_facts }}"
 
  tasks:
    - name: Check existing NTP Servers
        include_role:
        name: ntpcheck
        when: ansible_network_os is defined

    # Adds NTP server entries in the my_ntp_servers variable if the variable erase is false
    - block:
        - name: Compare NTP servers and remove erroneous entries
        cli_config:
            config: no {{ item }}
        loop: "{{ configured_servers }}"
        when:
            - configured_servers | length > 0
            - item not in required_servers

        - name: Ensure intended NTP servers are present
        cli_config:
            config: "{{ item }}"
        loop: "{{ required_servers }}"
        when: not erase|bool

    - name: Save template to temporary file
        template:
        src: report.j2
        dest: ./temp.html
        mode: '0755'
        when: in_servers | length > 0 or out_servers | length > 0

    # Creates and uploads a report to S3 
    - name: Upload report to S3
        aws_s3:
        bucket: "{{ my_bucket }}"
        src: "./temp.html"
        object: "index.html"
        mode: put
        metadata: 'Content-Type=text/html'
        when: in_servers | length > 0 or out_servers | length > 0

Output

The following output might be outdated.

⇨  ansible-playbook -i hosts ntp-compliance.yml --extra-vars='{"my_devices": "ios, iosxr", "my_facts": no, "my_bucket": "mydemo.run", "my_ntp_servers": [129.6.15.33, 132.163.96.5]}'

PLAY [NTP Server configuration compliance for Network Elements] *************************************************************************************************************************

TASK [Read inputs and prepare configs] **************************************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com] => (item=None)
ok: [sbx-iosxr-mgmt.cisco.com] => (item=None)
ok: [ios-xe-mgmt-latest.cisco.com] => (item=None)
ok: [ios-xe-mgmt-latest.cisco.com]
ok: [sbx-iosxr-mgmt.cisco.com] => (item=None)
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [Check existing NTP Servers] *******************************************************************************************************************************************************

TASK [ntpcheck : Check NTP config per vendor OS] ****************************************************************************************************************************************
included: /home/nleiva/Ansible/ansible-networking/roles/ntpcheck/tasks/ios.yml for ios-xe-mgmt-latest.cisco.com
included: /home/nleiva/Ansible/ansible-networking/roles/ntpcheck/tasks/iosxr.yml for sbx-iosxr-mgmt.cisco.com

TASK [ntpcheck : Get current NTP servers [IOS]] *****************************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com]

TASK [ntpcheck : Remove non config lines [IOS]] *****************************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com]

TASK [ntpcheck : Print current NTP servers [IOS]] ***************************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com] => {
    "configured_servers": [
        "ntp server 129.6.15.32",
        "ntp server 132.163.96.6"
    ]
}

TASK [ntpcheck : Generate data for reporting] *******************************************************************************************************************************************
included: /home/nleiva/Ansible/ansible-networking/roles/ntpcheck/tasks/report/data.yml for ios-xe-mgmt-latest.cisco.com

TASK [ntpcheck : Determine configuration delta for reporting [ios]] *********************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com]

TASK [ntpcheck : Create list of NEW servers to configure [ios]] *************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 129.6.15.33)
ok: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 132.163.96.5)

TASK [ntpcheck : Create list of servers to remove [ios]] ********************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 129.6.15.32)
ok: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 132.163.96.6)

TASK [ntpcheck : Print out fidings for reporting [ios]] *********************************************************************************************************************************
ok: [ios-xe-mgmt-latest.cisco.com] => {
    "msg": [
        "We are missing the following NTP Servers in IOS: ['129.6.15.33', '132.163.96.5']",
        "We will delete these NTP Servers in IOS: ['129.6.15.32', '132.163.96.6']"
    ]
}

TASK [ntpcheck : Get current NTP servers [IOS XR]] **************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [ntpcheck : Remove non config lines [IOS XR]] **************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [ntpcheck : Print current NTP servers [IOS XR]] ************************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => {
    "configured_servers": [
        "ntp server 129.6.15.32",
        "ntp server 132.163.96.6"
    ]
}

TASK [ntpcheck : Generate data for reporting] *******************************************************************************************************************************************
included: /home/nleiva/Ansible/ansible-networking/roles/ntpcheck/tasks/report/data.yml for sbx-iosxr-mgmt.cisco.com

TASK [ntpcheck : Determine configuration delta for reporting [iosxr]] *******************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com]

TASK [ntpcheck : Create list of NEW servers to configure [iosxr]] ***********************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 129.6.15.33)
ok: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 132.163.96.5)

TASK [ntpcheck : Create list of servers to remove [iosxr]] ******************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 129.6.15.32)
ok: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 132.163.96.6)

TASK [ntpcheck : Print out fidings for reporting [iosxr]] *******************************************************************************************************************************
ok: [sbx-iosxr-mgmt.cisco.com] => {
    "msg": [
        "We are missing the following NTP Servers in IOSXR: ['129.6.15.33', '132.163.96.5']",
        "We will delete these NTP Servers in IOSXR: ['129.6.15.32', '132.163.96.6']"
    ]
}

TASK [Compare NTP servers and remove erroneous entries] *********************************************************************************************************************************
changed: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 129.6.15.32)
changed: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 129.6.15.32)
changed: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 132.163.96.6)
changed: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 132.163.96.6)

TASK [Ensure intended NTP servers are present] ******************************************************************************************************************************************
changed: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 129.6.15.33)
changed: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 129.6.15.33)
changed: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 132.163.96.5)
changed: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 132.163.96.5)

TASK [Save template to temporary file] **************************************************************************************************************************************************
changed: [ios-xe-mgmt-latest.cisco.com]
changed: [sbx-iosxr-mgmt.cisco.com]

TASK [Upload report to S3] **************************************************************************************************************************************************************
changed: [ios-xe-mgmt-latest.cisco.com]
changed: [sbx-iosxr-mgmt.cisco.com]

TASK [Remove all existing NTP server entries] *******************************************************************************************************************************************
skipping: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 129.6.15.32) 
skipping: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 129.6.15.32) 
skipping: [ios-xe-mgmt-latest.cisco.com] => (item=ntp server 132.163.96.6) 
skipping: [sbx-iosxr-mgmt.cisco.com] => (item=ntp server 132.163.96.6) 

PLAY RECAP ******************************************************************************************************************************************************************************
ios-xe-mgmt-latest.cisco.com : ok=14   changed=4    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
sbx-iosxr-mgmt.cisco.com   : ok=14   changed=4    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0 

The report:

NTP report

What's inside

1 playbook, 1 role inclusion, 6 tasks, 1 Jinja2 template reference, and 1 S3 upload step

Change this for your project

  • Replace my_bucket value mydemo.run with your own S3 bucket name
  • Replace my_ntp_servers list [129.6.15.33, 132.163.96.5] with your required NTP server IPs
  • Replace my_devices pattern ios, iosxr with your own host groups or patterns
  • Replace report.j2 template path with your own Jinja2 report template

Where it goes

Use as the system prompt for your model call, or as the base instructions in your agent framework.

Worth borrowing

  • Using a role (ntpcheck) to encapsulate vendor-specific NTP parsing logic per OS
  • Generating a delta of required vs. configured servers before applying changes

Related Documents