Parsing cisco configs
Skill fastrevmd-lab/fwskillsshare/skills/parsing-cisco-configs
Agent skills for firewall work — parsing, auditing, converting, and running SRX. Works with Claude Code, Codex, and Hermes so far.
npx -y skills add fastrevmd-lab/fwskillsshare --skill parsing-cisco-configsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Parse Cisco ASA and FTD running configurations into the shared firewall schema. Use when input contains show running-config, access-list, access-group, object network, object-group, nameif, security-level, NAT, interfaces, or failover, including audit, conversion, diff, summary, and explanation tasks.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
24.3 KB, as published. Nobody here has run it
Parsing Cisco ASA / FTD Configurations
Overview
Use this skill to parse Cisco ASA and ASA-style FTD running configurations into the shared vendor-neutral firewall intermediate schema. It focuses on line-oriented show running-config text with parent commands and indented subcommands, including interfaces/nameifs, ACLs/access-groups, network and service objects, object-groups, NAT, routes, VPN, failover, and system settings.
Treat FMC-managed FTD exports and API data as adjacent but not identical inputs: parse what is present, preserve unresolved or unsupported structures in residual_raw, and call out assumptions rather than inventing missing policy context.
Scope and routing
Use only for Cisco ASA or FTD syntax. Hand off FortiOS config/edit/next/end blocks to parsing-fortinet-configs, PAN-OS XML or set deviceconfig to parsing-palo-configs, and Junos hierarchy or set security to parsing-srx-configs. Verify production-bound results against current device documentation and output. Downstream consumers are the audit, conversion, and diff skills.
Runtime intake
Before starting the workflow, inspect the request, supplied artifacts, and
available approved read-only evidence. If unresolved facts could materially
change safety, scope, correctness, confidence, or the requested output, read
references/runtime-intake.md.
For each unresolved material fact whose catalog condition is true, invoke Claude AskUserQuestion or Codex request_user_input before continuing or issuing an open-ended request.
Ask at most three single-select catalog questions per round. After each response, ask another round whenever any unresolved material catalog condition remains true; continue only when none remain. Do not repeat answered questions or show the full catalog.
Without a native tool, present each selected catalog question with its 2-3 labeled choices and a free-text Other path in concise plain text; do not substitute a generic checklist.
Never request secrets or unredacted customer data. Treat intake answers as task context, not approval for a live change; obtain separate explicit approval before configuration, commit, upgrade, reboot, delete, or failover actions.
Input Format
Cisco ASA configs are line-oriented with indented sub-commands:
interface GigabitEthernet0/0
nameif outside
security-level 0
ip address 203.0.113.1 255.255.255.0
!
object network web-server
host 10.0.1.10
nat (inside,outside) static 203.0.113.10
!
access-list outside_in extended permit tcp any object web-server eq 443
access-group outside_in in interface outside
Key syntax rules:
- Top-level commands start at column 0
- Sub-commands are indented with one space
!separates logical sections- Named interfaces use
nameif(e.g.,inside,outside,dmz) security-level(0-100) determines trust level
Building Command Blocks
Group indented lines under their parent top-level command — see references/parsing-patterns.md "Building Command Blocks" for the algorithm and worked example.
Extraction Pipeline
1. Interfaces
Source: interface <hardware-id> blocks
Extract from sub-commands:
nameif <name>— the logical name used everywhere elsesecurity-level <0-100>— trust levelip address <ip> <mask>— IP and subnet maskvlan <id>— VLAN assignmentshutdown— interface is administratively downdescription <text>bridge-group <id>— transparent mode bridge group membershipip address dhcp— DHCP client mode (no static IP)ipv6 address <ipv6/prefix> [eui-64]— IPv6 addressmtu <value>— MTU settingmanagement-only— management-only interface flagchannel-group <N>— LAG/EtherChannel membership (Port-channel parent)tunnel source interface <name>— VPN tunnel sourcetunnel destination <ip>— VPN tunnel destinationtunnel protection ipsec profile <name>— IPsec profile binding
Interface types: detect Port-channel* as lag, Tunnel* as tunnel, Loopback* as loopback, Management* as management. Sub-interfaces contain . in name (e.g., GigabitEthernet0/0.100) — derive parent from name before the dot.
2. Zones (Derived from Interfaces)
ASA doesn't have explicit zones. Derive them from nameif values:
- Each unique
nameifbecomes a zone security-levelvalues are parser-internal inference metadata used to determine relative trust ordering between zones (higher = more trusted). This is NOT emitted as asecurity_levelortrust_levelfield in the intermediate schema — use it only to guide ordering or warn when ACLs are absent.- Associate the interface with its zone
3. Network Objects
Source: object network <name> blocks
Types from sub-commands:
host <ip>→ type: "host", value: ip + "/32" (or "/128" for IPv6)subnet <ip> <mask>→ type: "subnet", value: ip + "/cidr" (convert mask to CIDR)range <start> <end>→ type: "range", value: "start-end"fqdn v4 <domain>orfqdn v6 <domain>→ type: "fqdn"
Note: bare fqdn <domain> (without v4/v6 qualifier) is also valid.
subnet <ipv6-prefix>→ for IPv6 subnets the value is already in CIDR form, no mask conversion needed.
Also extract: description, inline nat statement (for object/auto NAT).
4. Network Object Groups
Source: object-group network <name> blocks
Members from sub-commands:
network-object host <ip>→ inline hostnetwork-object <ip> <mask>→ inline subnetnetwork-object object <name>→ reference to named objectgroup-object <name>→ nested group reference
5. Service Objects
Source: object service <name> blocks
Parse: service <protocol> [source <op> <port>] [destination <op> <port>]
Operators: eq, range, gt, lt, neq
6. Service Object Groups
Source: object-group service <name> [<protocol>] blocks
Members:
port-object eq <port>/port-object range <start> <end>service-object <protocol> [destination <op> <port>]service-object object <name>group-object <name>
7. Protocol Object Groups
Source: object-group protocol <name> blocks
Members: protocol-object <protocol-name-or-number>
8. Access Lists (Security Policies)
Source: access-list <name> extended <action> <protocol> <src> <dst> [<svc>]
ACL Remarks:
access-list <name> remark <text> — attach as comment to the NEXT ACL entry.
ACL Line Parsing — Token by Token:
Format: access-list <id> extended <permit|deny> <protocol> <source> <dest> [<service>] [log] [time-range <name>]
Protocol field:
ip— any IP protocoltcp,udp,icmp,sctp— specific protocolsobject-group <name>— protocol group reference
Address parsing (for both source and destination):
any/any4/any6→ "any"host <ip>→ specific hostobject <name>→ named network objectobject-group <name>→ network object group<network> <mask>→ network/subnet-mask pair (convert standard subnet mask to CIDR)interface <nameif>→ the IP of that interface
Source port parsing (after source address, for TCP/UDP — optional):
eq <port>/range <start> <end>→ source port match (less common)
Service/port parsing (after destination address, for TCP/UDP):
eq <port>→ single port (use name or number)range <start> <end>→ port rangegt <port>→ greater thanlt <port>→ less thanneq <port>→ not equal (warn: limited cross-platform support)object-group <name>→ service group reference
ICMP parsing (for ICMP protocol):
- Optional ICMP type after destination:
icmp <src> <dst> <type> [<code>]
Flags:
log [<level>] [interval <secs>]→ enable loggingtime-range <name>→ schedule referenceinactive→ disabled
9. Access Groups (Binding ACLs to Interfaces/Zones)
Source: access-group <acl-name> <in|out> interface <nameif>
Also: access-group <acl-name> global (applies to all interfaces)
Critical: Deriving Zone-Based Policies from ACLs
ACLs alone don't have zone info. Combine with access-groups:
access-group outside_in in interface outside→ policies from this ACL have:src_zones: ["outside"](traffic enters on this interface, so it is the source zone)dst_zones:must be inferred (often "any" unless the ACL destination addresses map to a zone)
- For
indirection: traffic is entering the named interface, so that interface is the source zone - For
outdirection: traffic is leaving the named interface - For
global: applies regardless of interface
Build security policies by iterating ACL entries and attaching zone information from access-groups.
10. NAT Rules
Object NAT (Auto NAT):
Found inside object network blocks as nat (<real-iface>,<mapped-iface>) <type> <mapped-addr>
nat (inside,outside) static 203.0.113.10→ static 1:1 NATnat (inside,outside) dynamic interface→ dynamic PAT to interfacenat (inside,outside) dynamic pat-pool <name>→ dynamic PAT to pool
Twice NAT (Manual NAT):
Top-level: nat (<real-iface>,<mapped-iface>) [after-auto] [<line>] source <type> <real-src> <mapped-src> [destination <type> <real-dst> <mapped-dst>] [service <real-svc> <mapped-svc>]
Parse source static|dynamic and optional destination static components.
The optional numeric token is a line number — the rule's position within its manual NAT section — NOT a section selector. Derive the section from rule form: Section 1 = manual/twice NAT without after-auto (evaluated before object/auto NAT); Section 2 = object/auto NAT (rules inside object network blocks); Section 3 = manual NAT with the after-auto keyword (evaluated after all auto NAT).
11. Time Ranges (Schedules)
Source: time-range <name> blocks
Sub-commands:
absolute start <time> <date> end <time> <date>periodic <days> <start-time> to <end-time>
12. Routing
- Static routes (IPv4):
route <nameif> <dest> <mask> <gateway> [<metric>] - Static routes (IPv6):
ipv6 route <nameif> <dest/prefix> <gateway> [<metric>] - BGP:
router bgp <asn>block — extract:router-id,address-family ipv4 unicast- Per-neighbor:
remote-as,description,update-source,password,timers(keepalive/hold),next-hop-self,soft-reconfiguration,route-reflector-client,shutdown networkstatements (convert mask to CIDR)redistribute(connected/static)- Note: route-map and prefix-list references are not converted (warn)
- OSPF:
router ospf <pid>block — extract:router-id,auto-cost reference-bandwidthnetwork <ip> <wildcard> area <id>— match interfaces to areas via wildcard mask comparison- Area types: stub, nssa, with
no-summary; area default-cost; area authentication passive-interface default+no passive-interface <nameif>exceptionsredistribute(connected/static with metric/metric-type)- Interface-level:
ip ospf cost,ip ospf priority,ip ospf hello-interval,ip ospf dead-interval,ip ospf network point-to-point,ip ospf authentication message-digest+ key - Normalize area IDs to dotted-decimal (0 → 0.0.0.0)
- OSPFv3:
router ospfv3block withaddress-family ipv6 unicast— similar structure to OSPFv2
13. Infrastructure
- Hostname:
hostname <name>anddomain-name <domain>→ system metadata - Version:
asa version <X.Y>orfirepower version <X.Y>→ metadata.source_version - HA/Failover:
failoverpresence +failover lan unit primary|secondary(capture unit role),failover interface ip,failover link - Screen/Threat Detection:
threat-detection basic-threat+threat-detection rateentries - DNS:
dns server-group DefaultDNSblock → extractname-serverentries - NTP:
ntp server <ip> [prefer] - Management Access:
ssh|http|telnet <source> <mask> <nameif>— track which management protocols are accessible per zone - Admin Users:
username <name> password ... privilege <level>— map privilege 15=super-admin, 1-14=operator, 0=read-only.username <name> attributesblock withssh authentication publickey <key>for SSH keys. - VPN/IPsec:
crypto ikev2 policy <seq>blocks: encryption, integrity, DH group, lifetimecrypto ikev1 policy <seq>blocks: authentication, encryption, hash, DH group, lifetimecrypto ipsec ikev2 ipsec-proposal <name>: protocol esp encryption/integritycrypto ipsec ikev1 transform-set <name> <enc> <integ>crypto ipsec profile <name>: link proposals to PFS groupstunnel-group <ip> ipsec-attributes: PSK, certificates, authentication method- VTI assembly: match Tunnel interfaces to IPsec profiles, resolve tunnel source/destination, collect routes through tunnel nameifs
- Canonicalize algorithm names (ASA encryption names are mostly already canonical; e.g., sha → sha1, esp-3des → 3des)
- Flag weak algorithms (DES/3DES, MD5, DH group ≤ 5)
- Syslog:
logging host <nameif> <ip> - DHCP Server:
dhcpd address <start>-<end> <nameif>(pool range),dhcpd dns <ip1> [<ip2>],dhcpd domain <domain>,dhcpd lease <seconds>,dhcpd enable <nameif>(commit trigger — binds staged options to interface). Derive network CIDR from the interface IP. - DHCP Relay:
dhcprelay server <ip> <iface>+dhcprelay enable <nameif>
14. Application Mapping (L7 → Canonical)
ASA/FTD is a port-based platform — it does not have native L7 application awareness in ACLs. However, when converting FROM ASA to an app-aware platform (PAN-OS, FortiGate), or comparing configs, the parser should attempt to resolve well-known port/protocol combinations to canonical application names.
Resolution from port-based services: For each service object or inline port match, check if the protocol+port maps to a known application:
| Protocol | Port(s) | Canonical App | Category |
|---|---|---|---|
| TCP | 443 | https | web |
| TCP | 80 | http | web |
| TCP | 22 | ssh | remote-access |
| TCP | 3389 | rdp | remote-access |
| UDP | 53 | dns | network-mgmt |
| TCP | 25 | smtp | |
| TCP | 465 | smtps | |
| TCP | 993 | imaps | |
| TCP | 143 | imap | |
| UDP | 123 | ntp | network-mgmt |
| UDP | 161 | snmp | network-mgmt |
| UDP | 162 | snmp-trap | network-mgmt |
| TCP | 21 | ftp | file-transfer |
| TCP | 23 | telnet | remote-access |
| TCP | 389 | ldap | auth |
| TCP | 636 | ldaps | auth |
| UDP | 69 | tftp | file-transfer |
| TCP | 1433 | mssql | database |
| TCP | 3306 | mysql | database |
| TCP | 5432 | postgresql | database |
| TCP | 445 | smb | file-transfer |
| UDP | 500 | ipsec | tunnel |
| UDP | 4500 | ipsec-nat-t | tunnel |
| TCP | 5060 | sip | voip |
| UDP | 5060 | sip | voip |
ASA named port keywords: Map ASA port names to numbers before resolving — full table in references/parsing-patterns.md "Port Name Resolution". Caution: ASA literals predate IANA assignments (radius=1645, radius-acct=1646, kerberos=750) — do not "correct" them from prior knowledge; use the reference table.
On policy output: When a service match resolves to a known application, populate the policy's
apps array with { vendor_name: "tcp/443", canonical: "https", confidence: 1.0, category: "web" }.
The services array still keeps the port-based match. This enables downstream converters to use
the app-aware rule on platforms that support it.
Unresolvable services: Complex port ranges, non-standard ports, or protocol groups that don't
map to a single known application → keep as port-based services only, no apps entry.
15. Application Groups
ASA does not have application groups. However, when converting FROM an app-aware platform,
object-group service entries that resolve entirely to known applications should be flagged
as potential application_groups in the IR for downstream use.
16. Anonymous Objects
When inline addresses/services appear in ACLs or object groups without a named reference (e.g., host 10.0.1.10 directly in an ACL line), create anonymous objects with auto-generated names (e.g., anon-1-host, anon-2-net). This ensures every IR reference points to a named object.
17. Residual Config Capture
Capture unrecognized top-level commands verbatim. Categorize into: VPN/IPsec, AAA, QoS, PKI/Certificates, IPv6, Other. Store in residual_raw for manual review.
18. Transparent Mode
Detect: firewall transparent in config
When in transparent mode:
- Interfaces are in bridge-groups instead of having IPs
bridge-group <id>on interfaces- BVI interfaces (
interface BVI<id>) carry the management IP - Zones derived from nameifs still work the same way
19. Implicit Rules
The ASA implicit deny is scoped per bound ACL, not global: each ACL applied via access-group
ends with an implicit deny for that interface/direction only. Applying an ACL on one interface
does NOT disable security-level defaults for other interface pairs.
After building all policies from ACLs + access-groups, append:
- Implicit: Default Deny — one per access-group binding — action: "deny",
src_zones: [<bound nameif>]forindirection (dst_zonesforout; all any forglobal), remaining fields any,_implicit: true - When every traffic-passing interface has a bound ACL (or a
globalaccess-group exists), the per-binding denies may be collapsed into a single final any→any deny,_implicit: true - For interfaces with NO ACL bound: do not fabricate a deny — security-level defaults still
apply (higher-to-lower permitted, lower-to-higher denied). Add a
metadata.warningsentry ("no ACL bound on <nameif> — security-level high-to-low permit applies") and, if downstream consumers need explicit rules, model the default permit as an_implicit: trueallow policy from that zone to lower-security zones
Implicit-rule name values (e.g. "default-deny", "Implicit: Default Deny") are free-form labels; consumers must match implicit rules on _implicit: true, never on the name.
Output Format
Present results in the intermediate schema format documented in references/intermediate-schema.md.
Note: schema sections not yet populated by this pipeline (e.g., security_profile_objects, routing_contexts) are emitted empty ([]/{}); any unhandled source constructs are captured in residual_raw rather than dropped.
Full intermediate-schema emission is optional for single live-device work. The complete JSON schema exists primarily for cross-vendor conversion and multi-config diffing. When interpreting or auditing a single live device pulled via SSH/API for an ops/audit task, it is fine to reason directly from the running config and skip full schema emission — extract the sections relevant to the question. Emit the full schema when the parse will feed firewall-config-conversion, firewall-config-diff, or another config for comparison.
Parser Quality Gates
Before returning a parse, run these common quality gates and include the results in the response:
- Format and scope detection — report detected vendor, platform family, config format, version clues, virtual context names (VDOM/vsys/logical-system/routing-instance), and whether input appears complete or partial.
- Schema conformance — emit the vendor-neutral JSON sections defined in
references/intermediate-schema.md; use empty arrays/objects for absent sections rather than omitting expected top-level keys. - Object counts — summarize counts for zones, interfaces, address objects/groups, service/application objects/groups, policies, NAT rules, routes, VPNs, HA, admin users, and residual blocks.
- Reference resolution — list unresolved object, service/application, zone/interface, profile, route, VPN, and NAT references with source rule/context where possible.
- Ordering preservation — preserve security policy order, NAT order, route order when relevant, and inherited/pre/post/global ordering metadata with
_rule_indexor a vendor-specific context field. - State preservation — preserve disabled/inactive objects and rules, comments/descriptions, tags, schedules/time-ranges, negation flags, logging settings, and profile attachments.
- Residual capture — put unsupported or ambiguous source lines/blocks into
residual_rawwith enough context for manual review. Do not silently drop unknown syntax. - Warnings and assumptions — populate
metadata.warningswith parser limitations, partial-input assumptions, ambiguous conversions, and version-specific caveats. - Conversion readiness — if the user asks for migration/conversion, explicitly separate parsed facts from proposed target-platform design choices and call out non-isomorphic features.
A high-quality parse is not just valid JSON: it must make uncertainty visible. Prefer a complete parse with warnings and residuals over a clean-looking parse that hides unsupported constructs.
Analysis Checks
After extraction, run these checks and report findings:
- Unused objects — network/service objects not referenced in any ACL
- Shadowed ACL entries — rules that can never match due to earlier entries
- Overly permissive —
permit ip any anyor broad rules - Missing logging — permit ACL entries without
logkeyword - Inactive entries — ACL entries with
inactiveflag - Duplicate objects — same value, different names
- Empty groups — object-groups with no members
- Unbound ACLs — access-lists without matching access-group (never applied)
- Subnet mask validation — flag any non-standard subnet masks
Reference Files
references/config-format.md— Cisco ASA config syntax referencereferences/intermediate-schema.md— Output schema specificationreferences/parsing-patterns.md— Edge cases, port name mapping, security-level logicreferences/example-sample-parse.md— Worked end-to-end example (input config → parsed JSON)references/fixture-minimal-input.md— Minimal parser fixture inputreferences/fixture-expected-output.json— Expected high-level intermediate-schema output for the minimal fixture
Secret Handling
Never emit secrets raw. Tunnel-group pre-shared keys, username ... password hashes, BGP neighbor passwords, and SNMP community strings must be masked as "****" (or represented as a presence flag) with a metadata.warnings entry noting the secret was redacted — matching the shared-schema convention ("psk": "****").
Common Pitfalls
- Do not treat IOS wildcard masks as ASA subnet masks; ASA object subnets use standard dotted masks.
- Do not infer policy direction from ACL names alone; bind ACLs to interfaces with
access-group. - Object NAT and manual/twice NAT order matters. Preserve NAT section/order metadata and flag ambiguous translations.
- Security levels are not zones by themselves, but they help infer trust roles when no explicit design notes exist.
- FTD/FMC-managed output may omit policy context available in FMC; preserve gaps as warnings instead of fabricating rules.
Verification Checklist
- Input vendor/platform and config format were detected correctly
- All major object counts are reported: zones, interfaces, addresses, services/applications, policies, NAT, routes, VPN, HA, and system settings
- Output conforms to
references/intermediate-schema.md - Disabled/inactive rules and objects are preserved with explicit state
- Unresolved references, unsupported blocks, and parser assumptions are listed in
metadata.warningsand/orresidual_raw - Rule order and NAT order are preserved with
_rule_indexor equivalent ordering metadata - Cross-vendor conversion caveats are called out before suggesting target-platform config
- No raw secrets in output — PSKs masked as
"****", routing-protocol passwords/keys reduced to presence flags with warnings