[Day #35 Pyats Series] Parsing and validating access-lists (ACLs) using pyATS for Cisco [Python for Network Engineer]
Table of Contents
Introduction on the Key Points
Welcome to Day #35 of our “101 Days of pyATS (Vendor-Agnostic)” series exclusively designed for Network Engineers looking to automate their environments with ease. In today’s article, we’re focusing on Parsing and Validating Access-Control Lists (ACLs) using pyATS and Genie for Cisco devices.
Access Control Lists (ACLs) are critical for defining packet filtering behavior on routers and firewalls. Whether it’s a standard ACL used for filtering by source IP or extended ACLs filtering by protocol, port, and IP pair, consistent and correct ACL configuration is essential for a secure and functional network.
Using pyATS, Cisco’s powerful Python automation framework, we can extract, parse, and validate ACLs to ensure they match expected behavior. The best part? You can build this workflow once and reuse it across hundreds of devices — truly vendor-agnostic in spirit, scalable in design.
This guide is ideal for those exploring Python for Network Engineers who want to automate ACL compliance checks across production, staging, or lab environments.
Topology Overview
For today’s demonstration, our test environment will include a single Cisco IOS-XE router (CSR1000v). This is sufficient to showcase:
- ACLs applied on interfaces
- Parsing and validation using pyATS/Genie
- Real CLI vs Expected logic validation
Devices:
- R1 (Cisco CSR1000v)
Topology & Communications

- ACL Name:
BLOCK_TELNET
- ACL Rule: Deny TCP from any to any eq 23
- Objective: Ensure the ACL
BLOCK_TELNET
exists and is applied correctly.
Workflow Script (ACL Parsing & Validation)
Here’s the full pyATS
script using the Genie
parser for show access-lists
:
#!/usr/bin/env python from genie.testbed import load from genie.utils.diff import Diff import pprint # Load testbed testbed = load('testbed.yml') device = testbed.devices['R1'] device.connect(log_stdout=False) # Parse ACLs parsed_output = device.parse('show access-lists') # Define expected ACL (BLOCK_TELNET) expected_acl = { 'BLOCK_TELNET': { 'aces': { '10': { 'name': '10', 'matches': { 'l4': { 'destination_port': 'eq 23', 'protocol': 'tcp' }, 'l3': { 'source': 'any', 'destination': 'any' } }, 'actions': { 'forwarding': 'deny' } } } } } # Validate diff = Diff(parsed_output['BLOCK_TELNET'], expected_acl['BLOCK_TELNET']) print("\n=== Diff Result ===") if not diff.findDiff(): print(" ACL BLOCK_TELNET matches expected configuration.") else: pprint.pprint(diff.findDiff()) print(" ACL BLOCK_TELNET does not match expected configuration.")
Explanation by Line
load('testbed.yml')
loads the testbed file containing device credentials and connection details.device.connect()
establishes a connection to the router.device.parse('show access-lists')
uses Genie parsers to convert raw CLI to structured Python dictionary.- The expected ACL is defined using the exact logical structure Genie returns.
- The
Diff
object compares actual vs expected output and prints mismatches.
testbed.yml Example
testbed: name: ACL_Validation_TB credentials: default: username: cisco password: cisco devices: R1: os: iosxe type: router connections: cli: protocol: ssh ip: 192.168.1.1
This example uses SSH to connect to a CSR router. Ensure SSH is enabled on the device.
Post-validation CLI Screenshots (Real Expected Output)
After parsing ACLs with pyATS, you should expect the following parsed structure from CLI:
show access-lists
output:
Extended IP access list BLOCK_TELNET 10 deny tcp any any eq 23
Genie Parsed Output:
{ 'BLOCK_TELNET': { 'aces': { '10': { 'name': '10', 'matches': { 'l4': { 'protocol': 'tcp', 'destination_port': 'eq 23' }, 'l3': { 'source': 'any', 'destination': 'any' } }, 'actions': { 'forwarding': 'deny' } } } } }
The script validates this parsed structure against the expected dictionary.
FAQs
1] What is the purpose of parsing ACLs using pyATS Genie parsers?
Parsing ACLs with pyATS Genie parsers allows network engineers to convert raw CLI output into structured Python dictionaries. This makes it easy to automate
- Policy validation
- Security audit checks
- Compliance testing
- Misconfiguration detection (e.g., missing permit/deny rules)
By using this structured data, engineers can quickly loop through entries, validate presence of specific rules, or identify any unauthorized access permissions — all without manually inspecting CLI output.
2] Which CLI commands are supported for ACL parsing in Cisco IOS/IOS-XE with pyATS?
pyATS Genie supports parsing of the following ACL-related commands on Cisco IOS/IOS-X
show access-lists
show ip access-lists
show ipv6 access-lists
These commands can be parsed using:
device.parse("show ip access-lists")
The parser outputs structured dictionaries with each ACL name, sequence number, action (permit
/deny
), protocol, source/destination IPs, and more.
3] How do I validate if a specific rule exists inside an ACL using Python logic?
Once parsed, you can iterate through the dictionary to check if a particular rule is present. For example:
parsed_output = device.parse("show ip access-lists") acl_rules = parsed_output.get('acl', {}).get('MY_ACL', {}).get('aces', {}) for seq, rule in acl_rules.items(): if rule['actions']['forwarding'] == 'permit' and \ rule['matches']['l3']['ipv4']['protocol'] == 'tcp': print(f"TCP permit rule found at sequence: {seq}")
This helps validate existence and correctness of specific access policies.
4] Can pyATS compare current ACLs to a golden (reference) config?
Yes, pyATS allows diffing parsed outputs using genie.utils.diff
. You can take the parsed ACL from a golden snapshot and compare it with the current parsed output.
from genie.utils.diff import Diff diff = Diff(golden_acl_parsed, current_acl_parsed) diff.findDiff() print(diff)
This enables automated config drift detection and compliance monitoring.
5] What challenges may occur when parsing complex ACLs with nested remarks or object groups?
While pyATS handles most standard ACL formats, the parser may struggle or skip details when:
- ACLs use object-groups (Cisco ASA-style or modular ACLs)
- There are non-standard remarks or embedded scripts
- Very large ACLs with inconsistent spacing/indentation
For such cases, always validate the raw vs parsed outputs and log anomalies for deeper inspection.
6] How to validate IPv6 ACLs with pyATS?
Use the show ipv6 access-list
command for IPv6 ACL parsing.
parsed_ipv6_acl = device.parse("show ipv6 access-lists")
The structure is similar but includes IPv6-specific keys such as:
source_ipv6_network
destination_ipv6_network
icmpv6 type
This is crucial when validating security policies on dual-stack networks.
7] Can I write unit tests to ensure ACL rules are always present using pyATS AEtest or unittest?
Absolutely. You can write AEtest
test cases like this:
class VerifyACL(aetest.Testcase): @aetest.test def check_acl_rule(self): parsed = self.parent.parameters['parsed_acl'] assert 'MY_ACL' in parsed['acl'] assert any( rule['actions']['forwarding'] == 'deny' for rule in parsed['acl']['MY_ACL']['aces'].values() ), "No deny rule found in MY_ACL"
This ensures critical rules are always present as part of CI/CD pipelines or automated audits.
8] How can I extract just the ‘permit ip any any’ rules from all ACLs?
Use filtering logic on the parsed dictionary like:
permit_any_any = [] for acl_name, acl_data in parsed_output.get('acl', {}).items(): for seq, rule in acl_data.get('aces', {}).items(): if rule['actions']['forwarding'] == 'permit' and \ rule['matches']['l3']['ipv4'].get('source_network') == 'any' and \ rule['matches']['l3']['ipv4'].get('destination_network') == 'any': permit_any_any.append((acl_name, seq))
This helps identify overly permissive rules that may pose security risks.
YouTube Link
Watch the Complete Python for Network Engineer: Parsing and validating access-lists (ACLs) using pyATS for Cisco [Python for Network Engineer] Lab Demo & Explanation on our channel:
Join Our Training
If you’re excited about building more real-world, vendor-agnostic automation workflows like this one, Trainer Sagar Dhawan is conducting a 3-Month Instructor-Led Training focused on:
- Python for Network Engineers
- Ansible Automation
- Cisco pyATS + Genie
- NETCONF / RESTCONF / API & JSON/YAML
- DevNet Certification Prep
- Real-World Enterprise Projects
Course Details:
https://course.networkjourney.com/python-ansible-api-cisco-devnet-for-network-engineers/
Join hundreds of working professionals who’ve automated over 70% of their repetitive tasks using Python.
Master Python for Network Engineers and transform your career trajectory.
Reserve Your Spot NowEnroll Now & Future‑Proof Your Career
Email: info@networkjourney.com
WhatsApp / Call: +91 97395 21088