paloalto adapter

Features

The paloalto module manages Palo Alto Networks NGFW configuration through a Panorama (PAN-OS) management server, using the pan-os-python SDK. All resources connect to a single Panorama entity and are dispatched to a handler agent keyed on the Panorama hostname. The module models the core Panorama object hierarchy:

  • Device groups (DeviceGroup) — including parent hierarchy, reference templates and firewall membership.

  • Templates and template stacks (Template, TemplateStack) — with default vsys support.

  • Security zones (Zone) and network interfaces (Interface, L3SubInterface).

  • Logical routers / VRFs with BGP (RouteDomain) and BFD profiles (BfdProfile).

  • BGP peer groups and peers (BgpPeerGroup, BgpPeer) within a logical router’s VRF.

Beyond object CRUD, the module implements the Panorama commit/push workflow. A standalone Commit resource commits candidate config to Panorama (optionally scoped by admins, device_groups, templates, or forced), while Push pushes committed config from Panorama out to device groups or template stacks. In addition, DeviceGroup, Template and TemplateStack each carry committed and pushed booleans, letting a resource optionally commit (and push) its own scoped changes inline as part of its deploy. A FirewallConnection gate resource waits until a firewall is a connected member of a device group (useful for VM-Series bootstrap flows where the serial is unknown up front), and a DeploymentProfile entity plus generate_auth_key plugin provision Software NGFW licensing.

Api configuration

Resources connect through a paloalto::panorama::Panorama entity:

Attribute

Description

hostname

Panorama management address

username

API username

password

API password

Authentication is via the PAN-OS API username and password; the SDK obtains and uses an API key internally from these credentials. Every managed resource holds a panorama relation back to this entity, and runs on an agent selected by the Panorama hostname.

:bulb: Credentials for the Panorama connection are passed as plain entity attributes; the module reads no environment variables or config files for the connection itself. (The separate Licensing API used by DeploymentProfile takes its own OAuth2 client_id/client_secret, on its LicensingProvider.)

Usage example

import paloalto::panorama as pano

# Connect to Panorama (username/password auth)
p = pano::Panorama(
    hostname = "panorama.example.com",
    username = "admin",
    password = "<panorama-password>",
)

# A device group, with an inline scoped commit of its own changes
pano::DeviceGroup(
    panorama = p,
    name = "CustomerA",
    parent = "Shared",
    committed = true,
)

# A layer-3 interface in a template, and a security zone bound to it
interface = pano::Interface(
    panorama = p,
    name = "ethernet1/7",
    template = "zone_test_template",
    type = "layer3",
    ip_addresses = ["10.70.0.1/24"],
    mtu = 1400,
    comment = "zone-test-uplink",
    enable_dhcp = false,
)

zone = pano::Zone(
    panorama = p,
    name = "zone_test_integration",
    template = "zone_test_template",
    mode = "layer3",
    enable_user_id = true,
    log_setting = "zone-log-setting",
    interfaces = ["ethernet1/7"],
    enable_packet_buffer_protection = true,
    requires = [interface],
)

# A BGP peer group on the logical router's VRF, with one peer per remote node
peer_group = pano::BgpPeerGroup(
    panorama = p,
    name = "l3out_dif_diameter_a",
    template = "zone_test_template",
    route_domain = "effortel_diameter_a",
    filtering_profile_ipv4 = "allow_in_out",
)

peer_an1 = pano::BgpPeer(
    panorama = p,
    name = "aci_fl3out_an1_dif_diameter_a",
    template = peer_group.template,
    route_domain = peer_group.route_domain,
    peer_group = peer_group.name,
    peer_as = 4194305608,
    local_address_interface = "ethernet1/3.2267",
    peer_address = "172.29.132.17",
    requires = [peer_group],
)

peer_an2 = pano::BgpPeer(
    panorama = p,
    name = "aci_fl3out_an2_dif_diameter_a",
    template = peer_group.template,
    route_domain = peer_group.route_domain,
    peer_group = peer_group.name,
    peer_as = 4194305608,
    local_address_interface = "ethernet1/3.2267",
    peer_address = "172.29.132.18",
    requires = [peer_group],
)

# A standalone commit, scoped to a device group and template. It must require the
# resources it commits, otherwise it can run before or while they are deployed.
commit = pano::Commit(
    panorama = p,
    device_groups = ["Test_with_device"],
    templates = ["zone_test_template"],
    requires = [interface, zone, peer_group, peer_an1, peer_an2],
)

# Push committed config from Panorama out to the device group's firewalls
pano::Push(
    panorama = p,
    scope = "device_group",
    target = "Test_with_device",
    include_template = true,
    admins = ["admin"],
    requires = [commit],
)

Main entities

  • paloalto::panorama::Panorama — connection target holding Panorama hostname and API credentials.

  • paloalto::panorama::DeviceGroup — a Panorama device group (parent hierarchy, reference template, firewall membership).

  • paloalto::panorama::Firewall — a firewall identified by serial, referenced from a device group’s membership.

  • paloalto::panorama::Template / paloalto::panorama::TemplateStack — a template and an ordered stack of templates.

  • paloalto::panorama::Zone — a security zone within a template.

  • paloalto::panorama::Interface / paloalto::panorama::L3SubInterface — network interfaces and layer-3 subinterfaces.

  • paloalto::panorama::RouteDomain — a logical router / VRF with BGP configuration.

  • paloalto::panorama::BgpPeerGroup / paloalto::panorama::BgpPeer — a BGP peer group under a route-domain’s VRF, and a peer within such a group.

  • paloalto::panorama::BfdProfile — a BFD profile within a template.

  • paloalto::panorama::ManagementProfile — an interface management profile within a template.

  • paloalto::panorama::Commit / paloalto::panorama::Push — commit candidate config / push committed config to a scope.

  • paloalto::panorama::FirewallConnection — gate resource that waits until a named firewall is a connected member of a device group (read-only, not purgeable).

  • paloalto::panorama::DataplaneCores — enforces the VM-Series dataplane core count on a firewall reached through Panorama, using the vm_series plugin’s set-cores/dp-cores operational commands (day-2 drift only, not purgeable).

  • paloalto::LicensingProvider — Licensing API credentials shared by the deployment profiles, and the agent they run on. With mock=true the handler uses a mock licensing client instead.

  • paloalto::DeploymentProfile — Software NGFW flexible-sizing deployment profile provisioned via the Licensing API, through its provider.

  • generate_auth_key(hostname, username, password, lifetime=60, *, mock=false) — plugin generating a Panorama VM auth-key. With mock=true it returns a fixed key without contacting Panorama.

Notes and known limitations

  • Push drift cannot be reliably detected. Every deploy reports the push as pending to make sure pushes are attempted, so Push resources (and inline pushed flags) stay non-idempotent by design.

  • Device groups cannot be moved back into Shared. The PAN-OS API does not allow it; the handler raises an error if attempted (it can only be done via the Panorama UI).

  • FirewallConnection is read-only. It only observes membership/connectivity and does not create, update or delete.

  • Push scope constraints. include_template and device filtering are only valid for the device_group scope, not the template scope.

  • Commits only include the changes of the Panorama account. Panorama tracks pending changes per admin account, and every commit (Commit, and the inline committed flags) is scoped to the username of the Panorama entity, plus the additional accounts listed in Commit.admins. Give every orchestrator (or lab) sharing a Panorama its own account, so that they don’t commit each other’s pending changes.

  • A Commit must require the resources it commits. The module does not order a Commit after the configuration on its Panorama, since a device can have several scoped commits. Without requires, the orchestrator may run the commit before or during the changes it is meant to commit. Likewise, a Push should require its Commit.

  • BGP peers must require their peer group. A BgpPeer is nested inside its BgpPeerGroup on PAN-OS, so the group has to be deployed first; the handler fails with a lookup error if the group is missing.

  • A BGP peer always inherits from its peer group. pan-os-python does not model the peer’s inherit toggle, so the peer takes the address family and filtering profiles of its group, which is the PAN-OS default.

  • DataplaneCores never blocks on a reboot. Changing the core count only takes effect after a reboot; the handler issues the reboot and then skips (retrying on later deploys) until the firewall reconnects, rather than blocking the deploy on the reboot/reconnect cycle. Only the deploy that actually changes the configured count reboots — PAN-OS keeps reporting connected to Panorama for a while after accepting a restart, so a retry landing in that window would otherwise read the stale pre-reboot count and restart a firewall that is already going down. The trade-off: if a deploy dies between setting the count and issuing the restart, the resource skips until timeout turns it into a hard failure instead of rebooting the firewall on its own.

  • DataplaneCores is never purged. Tearing down the service that owns the firewall destroys the VM itself, so there is nothing on the (gone) device to reset.

  • DataplaneCores is operational-only. The dataplane/management-plane split lives outside /config on PAN-OS, so it cannot be delivered through a Panorama template/template-stack push; it is only ever set via a per-device operational command.