UFAYA
Unified Firewall Abstraction laYer for Automation
UFAYA is a Python SDK that provides a single, consistent interface for interacting with firewalls from multiple vendors. Instead of writing separate automation scripts for each firewall platform, UFAYA exposes a unified abstraction layer that normalizes firewall operations across different systems.
The design follows the same architectural principle used by tools like NAPALM, which provide a unified API to interact with devices from different vendors through an abstraction layer.
Supported Vendors
| Vendor | Driver | Status |
|---|---|---|
| Juniper SRX | juniper_srx |
Read-only XML ingestion + firewall-rule JSON export with live policy hit counts + XML-first NAT JSON export |
| Palo Alto | paloalto |
Planned |
| Fortinet | fortinet |
Planned |
| Cisco | cisco |
Planned |
Drivers can also be contributed out-of-tree and registered via the
ufaya.drivers entry-point group; see CONTRIBUTING.md.
Juniper SRX exports
JuniperSRXDriver.export_rules_json(output_dir, mode=...) writes a context-grouped JSON document for parsed security policies.
- Export modes remain
minimal,enriched, anddebug. - Export payloads now use
schema_version: 3. - Each exported rule includes a canonical
hit_countfield. - In live mode, UFAYA fetches
show security policies hit-count | display xml | no-moreand populateshit_countwhen that operational snapshot is available. - The live hit-count parser supports both older
policy-informationresponses and newer Junos operational XML variants such asmulti-routing-engine-resultswithpolicy-hit-count-entryrecords. - In file mode, or when the live hit-count snapshot cannot be collected, rules still include
hit_count: null. - Live exports that successfully collect hit counts also include a top-level
hit_counts_collected_atUTC timestamp. - Hit-count parser maintenance notes live in JUNIPER_HIT_COUNTS.md.
JuniperSRXDriver.export_nat_json(output_dir, mode=...) writes a context-grouped JSON document for parsed Junos NAT rules.
- NAT export is XML-first in both modes:
- live mode fetches
show configuration | display xml | no-more - file mode reads the XML file passed via
config_path
- live mode fetches
- NAT parsing walks
<security><nat><source>,<destination>, and<static>from configuration XML. - NAT export modes are also
minimal,enriched, anddebug. - NAT payloads use
schema_version: 2. - Exported NAT rules use a vendor-agnostic, rule-centric shape with explicit
conditions(traffic match) andmapping(before/after rewrite) blocks. conditionsdescribes which packets the rule selects;mappingdescribes what field is rewritten, from which addresses/ports, to which addresses/ports.- Each mapping step includes a human-readable
summary,original/translatedsides,mapping_kind(fixed/pool/interface_address),determinism(exact/set_based/dynamic), andresolution_status(resolved/unresolved). - Static NAT exports both
forward(inbound destination rewrite) andreverse(outbound source rewrite) mapping steps. - Unconstrained NAT address selectors export explicitly as
["any"]inconditions. - NAT
applicationreferences are resolved into canonical protocol/port condition fields while preserving raw application names. - Enriched and debug NAT exports also include referenced translation pools under
supporting_objects.translation_pools. supporting_objects.translation_poolsremains scoped to pools actually referenced by exported rules, not the full device inventory.- Referenced translation pools export the same normalized address/port values used by rule-level mapping targets, including supported address-range forms.
- NAT lookup metadata records Juniper precedence as
static, thendestination, thensource.
Installation
pip install ufaya
Command line
Export security policies or NAT rules directly from a saved Junos XML configuration:
ufaya export rules \
--vendor juniper_srx \
--config srx-prod.xml \
--out exports/ \
--mode enriched
ufaya export nat \
--vendor juniper_srx \
--config srx-prod.xml \
--out exports/ \
--mode enriched
--mode accepts minimal, enriched, or debug and defaults to enriched.
On success, the command prints the path of the generated JSON file. Invalid
vendors, missing or malformed configuration files, unsupported capabilities,
and unwritable output locations produce a concise error and a nonzero exit.
Usage
import ufaya
# File mode: parse a saved Junos XML config.
driver = ufaya.get_firewall_driver(
"juniper_srx",
config_path="srx-prod.xml",
)
rules = driver.get_rules()
# Live mode: SSH to the device. Use as a context manager so a single SSH
# session is shared across get_rules() and get_nat_rules() (and any future
# operational reads).
driver = ufaya.get_firewall_driver(
"juniper_srx",
host="srx-prod.example.com",
username="readonly",
password="...",
read_timeout=120, # Optional per-command timeout in seconds (default: 60).
)
with driver:
rules = driver.get_rules()
nat_rules = driver.get_nat_rules()
# Capability discovery: ask what the driver can do, rather than calling and
# catching NotImplementedError.
from ufaya.firewall.base import NatReader, FirewallWriter
assert isinstance(driver, NatReader) # supports NAT reads
assert not isinstance(driver, FirewallWriter) # read-only
Juniper live reads default to a 60-second timeout per configuration or hit-count
command. Set read_timeout on JuniperSRXDriver or through
get_firewall_driver() for slower devices or larger configurations. The value
must be finite and greater than zero; it does not change SSH connection or
authentication timeouts and is unused in file mode.
If the hit-count command raises, the driver closes that session and reconnects
before reading configuration. Successful configuration reads still return rules
with hit_count: null when counters are unavailable. Inside with driver:, the
replacement session is reused until the block exits. Configuration or reconnect
failures still raise ConnectionError; a session whose command read failed is
closed before another call can reuse it.
Out-of-tree drivers can register themselves via ufaya.register_driver(...) or by declaring a [project.entry-points."ufaya.drivers"] entry in their own pyproject.toml. See CONTRIBUTING.md.
JSON Schemas
The schemas/ directory publishes the canonical contract for each export type:
schemas/firewall_rules.v3.schema.json—JuniperSRXDriver.export_rules_json()output.schemas/nat_rules.v2.schema.json—JuniperSRXDriver.export_nat_json()output.
Both are strict (additionalProperties: false) Draft 2020-12 schemas. Downstream consumers can use them with any JSON Schema validator. The repo's CI fails any change that violates the contract; see CONTRIBUTING.md for the development flow.
Contributing
See CONTRIBUTING.md for guidelines.
License
Metadata
Release files for ufaya 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ufaya-0.8.0.tar.gz | 81.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ufaya-0.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 115.0 kB
Release files / ufaya-0.8.0.tar.gz
| Download URL | ufaya-0.8.0.tar.gz |
|---|---|
| Size | 81.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
200539159e4e625e41db175c026014a7a2620a92ec82856043d72365455bff69
|
|
BLAKE2b-256 checksum How to use checksums |
82daf48d2c3511095826d948e90e184b633e4a6ec5bb0fee0ac9b65fb24acff1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / ufaya-0.8.0-py3-none-any.whl
| Download URL | ufaya-0.8.0-py3-none-any.whl |
|---|---|
| Size | 33.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff20a225b17d54f58458c8cdd9c77cf7fd731b7a63f088ca7c6d9ddf7d26fa16
|
|
BLAKE2b-256 checksum How to use checksums |
44a982027fab6f707a21b3684ffb3f789dc60467a4442145940604dfc330f9c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency log