marksull / fmcapi

A Python package designed to help users of Cisco's FMC interface with its API.
BSD 3-Clause "New" or "Revised" License
81 stars 57 forks source link

ACPRule.put() action not passing through well #5

Closed brammeskens closed 5 years ago

brammeskens commented 6 years ago

I'm trying to edit existing rules through the API. More specifically all I want to change is switching source and destination zone. I obtain them in following lines:

`acprule = ACPRule(fmc=fmc1, acp_name=acpname) acprule.name = rule['name'] #rule has been obtained from a send_to_api function obtaining all policies in the ACP acprule.id = rule['id'] acprule.get()

                    acprule.sendEventsToFMC = True
                    acprule.logBegin = True
                    acprule.intrusion_policy(action='set', name='IPS-Balanced')
                    acprule.source_zone(action='clear')
                    acprule.destination_zone(action='add', name=src_zone)

                    print(acprule.format_data())

                    acprule.put()`

The rule gets obtained just fine with all metadata in the get function. Printing the format_data also lists that all information from the obtained rule is still there, plus the changes made to the rule. However, when I then try to put the changes to the API, the format_data function called in the API changes "ALLOW" to "BLOCK". Even if I manually set the action to allow before calling the put function.

Do you have any idea how the action-attribute gets lost the moment I call the put function? I'm still quite new to python, but have some experience in programming ... so I'm not sure if it's actually the fmcapi-module or not causing this.

The output of formate_data looks like this:

Before put:
{'id': 'acp_id', 'name': 'ACL_1', 'action': 'ALLOW', 'enabled': True, 'sendEventsToFMC': True, 'logFiles': False, 'logBegin': True, 'logEnd': False, 'variableSet': {'name': 'Default-Set', 'id': 'set_id', 'type': 'VariableSet'}, 'type': 'AccessRule', 'vlanTags': {}, 'sourceNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'my_group', 'id': 'group_id'}]}, 'destinationNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'any', 'id': 'group_id'}]}, 'destinationPorts': {'objects': [{'type': 'ProtocolPortObject', 'protocol': 'UDP', 'name': 'my_port', 'id': 'port_id'}, {'type': 'ProtocolPortObject', 'protocol': 'TCP', 'name': 'my_port2', 'id': 'port_id2'}]}, 'ipsPolicy': {'name': 'IPS-Balanced', 'id': 'ips_id', 'type': 'intrusionpolicy'}, 'destinationZones': {'objects': [{'name': 'INTERNET', 'id': 'zone_id', 'type': 'SecurityZone'}]}}

After put:
{'id': 'acp_id', 'name': 'ACL_1', 'action': 'BLOCK', 'enabled': True, 'sendEventsToFMC': True, 'logFiles': False, 'logBegin': False, 'logEnd': False, 'variableSet': {'name': 'Default-Set', 'id': 'set_id', 'type': 'VariableSet'}, 'type': 'AccessRule', 'vlanTags': {}, 'sourceNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'my_group', 'id': 'group_id'}]}, 'destinationNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'any', 'id': 'group_id'}]}, 'destinationPorts': {'objects': [{'type': 'ProtocolPortObject', 'protocol': 'UDP', 'name': 'my_port', 'id': 'port_id'}, {'type': 'ProtocolPortObject', 'protocol': 'TCP', 'name': 'my_port2', 'id': 'port_id2'}]}, 'ipsPolicy': {'name': 'IPS-Balanced', 'id': 'ips_id', 'type': 'intrusionpolicy'}, 'destinationZones': {'objects': [{'name': 'INTERNET', 'id': 'zone_id', 'type': 'SecurityZone'}]}}
daxm commented 6 years ago

My apologies for being so slow to get back to you. I'd like to talk with you some more about this issue to see how I can fix it. I'm "old fashioned" and would prefer to talk with you (maybe even share a desktop to see the issue). Would you be open for that? If so, what is your phone number and can you give me a few times that work for you to talk?

On 2018-05-17 05:58, brammeskens wrote:

I'm trying to edit existing rules through the API. More specifically all I want to change is switching source and destination zone. I obtain them in following lines:

`acprule = ACPRule(fmc=fmc1, acp_name=acpname) acprule.name = rule['name'] #rule has been obtained from a send_to_api function obtaining all policies in the ACP acprule.id = rule['id'] acprule.get()

                acprule.sendEventsToFMC = True
                acprule.logBegin = True
                acprule.intrusion_policy(action='set',

name='IPS-Balanced') acprule.source_zone(action='clear') acprule.destination_zone(action='add', name=src_zone)

                print(acprule.format_data())

                acprule.put()`

The rule gets obtained just fine with all metadata in the get function. Printing the format_data also lists that all information from the obtained rule is still there, plus the changes made to the rule. However, when I then try to put the changes to the API, the format_data function called in the API changes "ALLOW" to "BLOCK". Even if I manually set the action to allow before calling the put function.

Do you have any idea how the action-attribute gets lost the moment I call the put function? I'm still quite new to python, but have some experience in programming ... so I'm not sure if it's actually the fmcapi-module or not causing this.

The output of formate_data looks like this: Before put: {'id': 'acp_id', 'name': 'ACL_1', 'action': 'ALLOW', 'enabled': True, 'sendEventsToFMC': True, 'logFiles': False, 'logBegin': True, 'logEnd': False, 'variableSet': {'name': 'Default-Set', 'id': 'set_id', 'type': 'VariableSet'}, 'type': 'AccessRule', 'vlanTags': {}, 'sourceNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'my_group', 'id': 'group_id'}]}, 'destinationNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'any', 'id': 'group_id'}]}, 'destinationPorts': {'objects': [{'type': 'ProtocolPortObject', 'protocol': 'UDP', 'name': 'my_port', 'id': 'port_id'}, {'type': 'ProtocolPortObject', 'protocol': 'TCP', 'name': 'my_port2', 'id': 'port_id2'}]}, 'ipsPolicy': {'name': 'IPS-Balanced', 'id': 'ips_id', 'type': 'intrusionpolicy'}, 'destinationZones': {'objects': [{'name': 'INTERNET', 'id': 'zone_id', 'type': 'SecurityZone'}]}}

After put: {'id': 'acp_id', 'name': 'ACL_1', 'action': 'BLOCK', 'enabled': True, 'sendEventsToFMC': True, 'logFiles': False, 'logBegin': False, 'logEnd': False, 'variableSet': {'name': 'Default-Set', 'id': 'set_id', 'type': 'VariableSet'}, 'type': 'AccessRule', 'vlanTags': {}, 'sourceNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'my_group', 'id': 'group_id'}]}, 'destinationNetworks': {'objects': [{'type': 'NetworkGroup', 'name': 'any', 'id': 'group_id'}]}, 'destinationPorts': {'objects': [{'type': 'ProtocolPortObject', 'protocol': 'UDP', 'name': 'my_port', 'id': 'port_id'}, {'type': 'ProtocolPortObject', 'protocol': 'TCP', 'name': 'my_port2', 'id': 'port_id2'}]}, 'ipsPolicy': {'name': 'IPS-Balanced', 'id': 'ips_id', 'type': 'intrusionpolicy'}, 'destinationZones': {'objects': [{'name': 'INTERNET', 'id': 'zone_id', 'type': 'SecurityZone'}]}}

-- You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub [1], or mute the thread [2].

*

Links:

[1] https://github.com/daxm/fmcapi/issues/5 [2] https://github.com/notifications/unsubscribe-auth/ADLmZwe15xYKv9KWYyKioJq1hrpAVWmEks5tzWX6gaJpZM4UC7ge

mgdransfield commented 5 years ago

The problem seems to be that parse_kwargs is using else clauses to set defaults when an argument is not present and is called from put after an object is already instantiated. This effectively resets some arguments to default such as action to BLOCK. Removing the else... statements from parse_kwargs fixes this but I am not sure if it may have other unwanted effects.

daxm commented 5 years ago

The problem seems to be that parse_kwargs is using else clauses to set defaults when an argument is not present and is called from put after an object is already instantiated. This effectively resets some arguments to default such as action to BLOCK. Removing the else... statements from parse_kwargs fixes this but I am not sure if it may have other unwanted effects.

I could see that. I'll look into it when I get a chance.

shaktikshri commented 5 years ago

As @mgdransfield pointed out, the issue is in the else clause for ‘action' (and other fields which are required for PUT by default at the FMC server) in kwargs in method ACPRule.parse_kwargs

if 'action' in kwargs:
    if kwargs['action'] in self.VALID_FOR_ACTION:
        self.action = kwargs['action']
    else:
        logging.warning('Action {} is not a valid action.'.format(kwargs['action']))
else:
    self.action = ‘BLOCK'

A workaround is,

  1. do a get() on the object first
  2. change any fields you want
  3. pass all the fields of ACPRule object as arguments in the PUT method

acprule = ACPRule(fmc=fmc1, acp_name=acpname)
acprule.name = rule['name']
acprule.id = rule['id']

# Get the current configuration
acprule.get()
# now you have a field acprule.action set to your current value at the FMC

acprule.sendEventsToFMC = True
acprule.logBegin = True
acprule.intrusion_policy(action='set', name='IPS-Balanced')
acprule.source_zone(action='clear')
acprule.destination_zone(action='add', name=src_zone)

# pass all the fields as arguments to ACPRule's PUT method,
# so that none of the required fields (in your case 'action') assume default 
# values as dictated by the else clauses in parse_kwargs
acprule.put(**acp_rule.__dict__)
daxm commented 5 years ago

shaktishri, good point. To get "non-default" values you need to get() your object from the FMC prior to making any changes. Should I consider this issue closed?

shaktikshri commented 5 years ago

I think we need to make this addition in the ACPRule definition. This workaround especially

acprule.get()
acprule.put(**acp_rule.__dict__)

looks very non-intuitive. I’ll take this issue for fixing.

daxm commented 5 years ago

I think we need to make this addition in the ACPRule definition. This workaround especially

acprule.get()
acprule.put(**acp_rule.__dict__)

looks very non-intuitive. I’ll take this issue for fixing.

Any progress on this? Looking at the ACPRule class' parse_kwargs function I see where the "offending" code is. I could easily just comment out the setting of the action if it isn't present at instantiation. I don't remember why I put this in there in the first place!

daxm commented 5 years ago

I removed the "if not Action not set then set it to BLOCK" code. So, you shouldn't get a BLOCK set by default anymore. This is in release 20180828.0