PaloAltoNetworks / pan-os-python

The PAN-OS SDK for Python is a package to help interact with Palo Alto Networks devices (including physical and virtualized Next-generation Firewalls and Panorama). The pan-os-python SDK is object oriented and mimics the traditional interaction with the device via the GUI or CLI/API.
https://pan-os-python.readthedocs.io
ISC License
340 stars 168 forks source link

Not able to create a rule #455

Closed martino76 closed 2 years ago

martino76 commented 2 years ago

Describe the bug

When trying to create a rule using SecurityRule method it's failing.

Expected behavior

Rule should be created on the firewall.

Current behavior

My code is as follow

from panos.firewall import Firewall
from panos.policies import Rulebase, SecurityRule

fw = Firewall("192.168.1.14", "admin", "admin")
base = Rulebase()
fw.add(base)

rule = SecurityRule(
        name="TEST",
        fromzone="INSIDE",
        tozone="OUTSIDE",
        source=["any"],
        source_user=["any"],
        hip_profiles=["any"],
        destination=["any"],
        application=["any"],
        action="allow",
    )
try:
    base.add(rule)
    rule.create()

I am getting following error

Traceback (most recent call last):
  File "/home/marcin/.local/lib/python3.9/site-packages/panos/base.py", line 3878, in method
    super_method(self, *args, **kwargs)
  File "/home/marcin/.local/lib/python3.9/site-packages/pan/xapi.py", line 741, in set
    self.__type_config('set', query, extra_qs)
  File "/home/marcin/.local/lib/python3.9/site-packages/pan/xapi.py", line 805, in __type_config
    raise PanXapiError(self.status_detail)
pan.xapi.PanXapiError:  TEST -> source-hip unexpected here

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/marcin/scripts/paloalto_create_rule.py", line 25, in <module>
    rule.create()
  File "/home/marcin/.local/lib/python3.9/site-packages/panos/base.py", line 652, in create
    device.active().xapi.set(
  File "/home/marcin/.local/lib/python3.9/site-packages/panos/base.py", line 3899, in method
    raise the_exception
panos.errors.PanDeviceXapiError:  TEST -> source-hip unexpected here

Possible solution

It work when add try and repeat creation of a rule

from panos.firewall import Firewall
from panos.policies import Rulebase, SecurityRule
from panos import errors

fw = Firewall("192.168.1.14", "admin", "admin")
base = Rulebase()
fw.add(base)

rule = SecurityRule(
        name="TEST",
        fromzone="INSIDE",
        tozone="OUTSIDE",
        source=["any"],
        source_user=["any"],
        hip_profiles=["any"],
        destination=["any"],
        application=["any"],
        action="allow",
    )
try:
    base.add(rule)
    rule.create()
except errors.PanDeviceXapiError as e:
    base.add(rule)
    rule.create()
welcome-to-palo-alto-networks[bot] commented 2 years ago

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

shinmog commented 2 years ago

Using the current pan-os-python, I am unable to reproduce your error. Maybe you need to upgrade pan-os-python or something...?

try:
    from unittest import mock
except ImportError:
    import mock

from panos.firewall import Firewall
from panos.policies import SecurityRule, Rulebase

def get_rule(versionTuple):
    fw = Firewall('a', 'b', 'c', 'd')
    fw._version_info = versionTuple

    base = Rulebase()
    fw.add(base)

    rule = SecurityRule(
        name="TEST",
        fromzone="INSIDE",
        tozone="OUTSIDE",
        source=["any"],
        source_user=["any"],
        hip_profiles=["any"],
        destination=["any"],
        application=["any"],
        action="allow",
    )   
    base.add(rule)

    return rule

def test_exclude_source_and_destination_devices():
    rule = get_rule((9, 1, 0))

    assert "source-hip" not in rule.element_str().decode("utf-8")
    assert "destination-hip" not in rule.element_str().decode("utf-8")

def test_include_source_and_destination_devices():
    rule = get_rule((10, 0, 0))

    assert "source-hip" in rule.element_str().decode("utf-8")
    assert "destination-hip" in rule.element_str().decode("utf-8")
shinmog commented 2 years ago

Just realized I should explain why I'm doing what I did above.

The error suggests that pan-os-python is attempting to send the source-hip parameter to PAN-OS. This would be incorrect because you said that you're running against PAN-OS 9.1.0. So I did the above to check and verify that when pan-os-python sees something under 10.00, it should not be sending the source-hip / destination-hip XML nodes.

My above unit tests prove that pan-os-python is doing the right thing.

That being said, looking at your code, when you add an object to another, it won't throw an exception, you only need to wrap the .create(). But pan-os-python wouldn't be sending something different the second time, so the code that you have above where it just tries again and it suddenly works is really weird to me.

If after doing base.add(rule), can you do this and see what you get?

from panos.firewall import Firewall
from panos.policies import Rulebase, SecurityRule

fw = Firewall("192.168.1.14", "admin", "admin")

base = Rulebase()
fw.add(base)

rule = SecurityRule(
        name="TEST",
        fromzone="INSIDE",
        tozone="OUTSIDE",
        source=["any"],
        source_user=["any"],
        hip_profiles=["any"],
        destination=["any"],
        application=["any"],
        action="allow",
)
base.add(rule)

# In your code, the "just run it a second time" is weird to me,
# so we're going to make the XML element twice
# and see what we get before trying to send it to PAN-OS.
t1 = rule.element_str().decode("utf-8")
t2 = rule.element_str().decode("utf-8")

# Do some quick tests.  Since this is running against PAN-OS 9.1,
# the source-hip won't be present in the XML.
assert t1 == t2
assert "source-hip" not in t1

# If the above both worked, then this will work just fine without raising an exception now.
rule.create()
martino76 commented 2 years ago

Looks like below code works for me. So you can close the thread.

for k,v in rule_dict.items():
    base = fw.add(Rulebase())
    rule =  base.add(SecurityRule(
            name=v['name'],
            fromzone=v['fromzone'],
            tozone=v['tozone'],
            source=v['source'],
            source_user=["any"],
            hip_profiles=["any"],
            destination=v['destination'],
            application=["any"],
            action="allow",
            group='SG_PROFILE'
        ))
    rule.create()
martino76 commented 2 years ago

The code I pasted solve my issue.