pan-os-ansible icon indicating copy to clipboard operation
pan-os-ansible copied to clipboard

Manipulate software configuration

Open telekomancer opened this issue 1 year ago • 10 comments

Is your feature request related to a problem?

I'm trying to add some additional configuration to the firewall with panos_op commands, now i understand that some commands aren't part of software configuration more related to operational parameters (app, auth ... blah blah), but there are some commands that are out of that scope, for example:

set network virtual-router VR-1 protocol ospf enable yes

And a long list of commands that we need on a daily basis.

Describe the solution you'd like

Add a module to allow configure & set commands something like paloaltonetworks.panos.panos_set module

With loop support, something like:

- name: fix all unsupported commands
  paloaltonetworks.panos.panos_set:
    provider: '{{ provider }}'
    cmd: 'set cli config-output-format set
              configure
              set network virtual-router VR-1 protocol ospf enable yes
              set network virtual-router VR-1 protocol ospf area 0.0.0.0 type normal 
              ....'

Describe alternatives you've considered

A direct access to CLI (set mode) to execute not supported commands

Additional context

I try to migrate all PANOS-FW configuration to ansible, but i cannot migrate:

  • OSPF
  • LLDP-Profiles
  • DHCP Servers
  • Log-settings
  • server-profiles
  • ...

A piece of code:

set shared log-settings syslog SSP server server1 transport TCP
set shared log-settings syslog SSP server server1 port 2514
set shared log-settings syslog SSP server server1 format BSD
set shared log-settings syslog SSP server server1 server 192.168.1.2
set shared log-settings syslog SSP server server1 facility LOG_LOCAL7
set shared log-settings snmptrap SNMPTrapServerProfile version v2c server abc manager 192.168.1.2
set shared log-settings snmptrap SNMPTrapServerProfile version v2c server abc community PANOS-FW
set shared log-settings system match-list LSS-Routing send-snmptrap SNMPTrapServerProfile
set shared log-settings system match-list LSS-Routing filter "((severity eq informational) or (severity eq high)) and (subtype eq routing) and (( eventid eq routed-OSPF-neighbor-full ) or ( eventid eq routed-OSPF-neighbor-down ) or ( eventid eq routed-OSPF-neighbor-2dir ))"
set shared log-settings system match-list LSS-Routing send-syslog SSP
set shared server-profile netflow NFSP-EF server flowserver host 192.168.1.21
set shared server-profile netflow NFSP-EF server flowserver port 2055
set shared server-profile netflow NFSP-EF server flowserver2 host 192.168.1.21
set shared server-profile netflow NFSP-EF server flowserver2 port 9995
set shared server-profile netflow NFSP-EF template-refresh-rate minutes 1
set shared server-profile netflow NFSP-EF template-refresh-rate packets 20
set shared server-profile netflow NFSP-EF active-timeout 5
set shared server-profile netflow NFSP-EF export-enterprise-fields yes

telekomancer avatar Mar 22 '23 21:03 telekomancer

:tada: Thanks for opening your first issue here! Welcome to the community!

Thanks for the suggestion @telekomancer

(You shared a syslog server profile in the piece of code, there is actually a module for that)

In the meantime, you could investigate panos_type_cmd and panos_config_element, which allow the configuration of arbitrary items as you described, but using XML instead of "set" commands. The set commands you have today could be converted to XML using the debug feature of the CLI, or by looking at the config XML from a config backup or on the CLI, using netflow as an example:

> set cli config-output-format xml
> configure
Entering configuration mode
[edit]                                                                                                                                                                                                                        
# show shared server-profile netflow
<response status="success" code="19">
  <result total-count="1" count="1">
    <netflow>
      <entry name="NFSP-EF">
        <server>
          <entry name="flowserver">
            <host>192.168.1.21</host>
            <port>2055</port>
          </entry>
          <entry name="flowserver2">
            <host>192.168.1.21</host>
            <port>9995</port>
          </entry>
        </server>
        <template-refresh-rate>
          <minutes>1</minutes>
          <packets>20</packets>
        </template-refresh-rate>
        <active-timeout>5</active-timeout>
        <export-enterprise-fields>yes</export-enterprise-fields>
      </entry>
    </netflow>
  </result>
</response>

This leads us to a netflow task like this as an example:

    - name: Create Netflow details with config_element
      paloaltonetworks.panos.panos_config_element:
        provider: "{{ device }}"
        xpath: '/config/shared/server-profile/netflow'
        element: |
          <entry name="NFSP-EF">
          <server>
          <entry name="flowserver"><host>192.168.1.21</host><port>2055</port></entry>
          <entry name="flowserver2"><host>192.168.1.21</host><port>9995</port></entry>
          </server>
          <template-refresh-rate><minutes>1</minutes><packets>20</packets></template-refresh-rate>
          <active-timeout>5</active-timeout>
          <export-enterprise-fields>yes</export-enterprise-fields>
          </entry>

jamesholland-uk avatar Mar 24 '23 09:03 jamesholland-uk

Looks good.

Now, to be specific, i have a problem related to OSPF module

image

Config, at task level is:

---
- hosts: all
  connection: local
  gather_facts: False

  vars:
    provider:
     ip_address: '192.168.0.1'
     username: "{{lookup('env','USERNAME')}}"
     password: "{{lookup('env','PASSWORD')}}"
    device:
     ip_address: '192.168.0.1'
     username: "{{lookup('env','USERNAME')}}"
     password: "{{lookup('env','PASSWORD')}}"
     
  tasks:
  
    - name: Create ospf details with config_element
      paloaltonetworks.panos.panos_config_element:
        provider: "{{ device }}"
        xpath: '/config/network/virtual-router/VR-1/protocol/ospf'
        element: |
          <ospf>
          <enable>yes</enable>
          <area>
          <entry name="0.0.0.0">
          <type>
          <normal/>
          </type>
          <interface>
          <entry name="ethernet1/3">
          <enable>yes</enable>
          <passive>no</passive>
          <authentication>VR-OSPF-Auth</authentication>
          <gr-delay>10</gr-delay>
          <metric>10</metric>
          <priority>1</priority>
          <hello-interval>10</hello-interval>
          <dead-counts>4</dead-counts>
          <retransmit-interval>5</retransmit-interval>
          <transit-delay>1</transit-delay>
          <link-type>
          <broadcast/>
          </link-type>
          </entry>
          </interface>
          </entry>
          </area>
          <auth-profile>
          <entry name="VR-OSPF-Auth">
          <md5>
          <entry name="1">
          <preferred>yes</preferred>
          <key>-AQ==f/d2OG9IawKv22mx/X5e3IcrS8=Ng12lxk4VeyPdr5b4vnpq==</key>
          </entry>
          </md5>
          </entry>
          </auth-profile>
          <router-id>192.168.0.1</router-id>
          <allow-redist-default-route>no</allow-redist-default-route>
          <rfc1583>yes</rfc1583>
          </ospf>

And CLI output:

admin@paloalto# show network virtual-router VR-1 protocol ospf | match enable
      <enable>yes</enable>
              <enable>yes</enable>
[edit]

Maybe the request should be pointing to another URL ?

telekomancer avatar Mar 24 '23 12:03 telekomancer

Hi @telekomancer, Doing the "debug the CLI" method will get you the xpath, and yes, it needed a small modification:

# set network virtual-router VR-1 protocol ospf

(container-tag: network container-tag: virtual-router container-tag: entry key-tag: name value: VR-1 container-tag: protocol container-tag: ospf)
((eol-matched: . #t) (eol-matched: . #t) (xpath-prefix: . /config/devices/entry[@name='localhost.localdomain']) (context-inserted-at-end-p: . #f))
(network (virtual-router (entry (@ (name VR-1)) (protocol (ospf)))))
(ospf)

<request cmd="set" obj="/config/devices/entry[@name='localhost.localdomain']/network/virtual-router/entry[@name='VR-1']/protocol" cookie="7812769761405011"><ospf/></request>

From that we see this is the xpath: /config/devices/entry[@name='localhost.localdomain']/network/virtual-router/entry[@name='VR-1']/protocol

Then from your code above, the key for the auth profile was too long, maximum is 16 chars: Screenshot 2023-03-24 at 13 13 20 Once this was reduced, the config seemed to work ok for me: Screenshot 2023-03-24 at 13 14 11

Hope that helps

jamesholland-uk avatar Mar 24 '23 13:03 jamesholland-uk

Sorry for the slow replies, am checking before answer back to you.

Ok, looks reasonable.

And looks like both modules should complete all the "not cover" configuration of other modules, i'll keep this issue open until i can migrate all config to 100% ansible.

Meanwhile i guess that could be very helpful to add the comment that you did "..."debug the CLI"..." to both modules.

telekomancer avatar Mar 24 '23 14:03 telekomancer

Ok, i'll try to migrate all the config, but i have an error like this:

TASK [Create dhcp-server ae1.20 details with config_element] *******************
fatal: [firewall]: FAILED! => {"changed": false, "msg": "Edit breaks config validity"}

I checked on panos_config_element for some help and I only see

...
edit 
boolean 

 If **true**, replace any existing configuration at the specified location with the contents of *element*. 
If **false**, merge the contents of *element* with any existing configuration at the specified location. 
...

I checked the error and read this page so now the question is, how do i fix that ?

telekomancer avatar Mar 30 '23 16:03 telekomancer

Hi @telekomancer, in order to comment further we would need to see the code for the Create dhcp-server ae1.20 task

jamesholland-uk avatar Apr 03 '23 10:04 jamesholland-uk

    - name: Create dhcp-server ae1.20 details with config_element
      paloaltonetworks.panos.panos_config_element:
        provider: "{{ device }}"
        edit: true
        xpath: '/config/devices/entry[@name="localhost.localdomain"]/network/dhcp/interface/entry[@name="ae1.20"]/server'
        element: |
          <entry name="ae1.20">
          <server>
          <option>
          <dns>
          <primary>8.8.8.8</primary>
          <secondary>8.8.4.4</secondary>
          </dns>
          <lease>
          <timeout>480</timeout>
          </lease>
          <gateway>172.16.16.1</gateway>
          <subnet-mask>255.255.255.0</subnet-mask>
          </option>
          <ip-pool>
          <member>172.16.16.2-172.16.16.254</member>
          </ip-pool>
          <mode>auto</mode>
          <probe-ip>yes</probe-ip>
          </server>
          </entry>

telekomancer avatar Apr 03 '23 12:04 telekomancer

Hi @telekomancer,

Do you already have a DHCP server on ae1.20 before you run this playbook, and you are modifying the config of that DHCP server? If so, it will work, because you are using edit: true.

If there is no DHCP server already existing on ae1.20, you need something like this, because the entry for ae1.20 does not exist and we can not use edit:

    - name: Create dhcp-server ae1.20 details with config_element
      paloaltonetworks.panos.panos_config_element:
        provider: "{{ device }}"
        xpath: "/config/devices/entry[@name='localhost.localdomain']/network/dhcp/interface"
        element: |
          <entry name="ae1.20">
          <server>
          <option>
          <dns>
          <primary>8.8.8.8</primary>
          <secondary>8.8.4.4</secondary>
          </dns>
          <lease>
          <timeout>480</timeout>
          </lease>
          <gateway>172.16.16.1</gateway>
          <subnet-mask>255.255.255.0</subnet-mask>
          </option>
          <ip-pool>
          <member>172.16.16.2-172.16.16.254</member>
          </ip-pool>
          <mode>auto</mode>
          <probe-ip>yes</probe-ip>
          </server>
          </entry>

jamesholland-uk avatar Apr 03 '23 16:04 jamesholland-uk

DHCP Server(s) already exist, this config file are created in case that i need to redeploy the firewall, in case of full disaster recovery and the need of reconfigure all from scratch, so i guess that there's no need to configure again the DHCP server, more over, i guess that i need to add a "ignore_errors: true" in all steps that already exist on firewall and make CI/CD fail (for example DHCP Server configuration).

telekomancer avatar Apr 03 '23 16:04 telekomancer