def main(): helper = get_connection( vsys=True, with_classic_provider_spec=True, panorama_error='Panorama is not supported', argument_spec=dict( rule_type=dict(default='security', choices=['security', 'nat']), source_zone=dict(), source_ip=dict(required=True), source_port=dict(type='int'), source_user=dict(), to_interface=dict(), destination_zone=dict(), destination_ip=dict(required=True), destination_port=dict(required=True, type='int'), application=dict(), protocol=dict(required=True, type='int'), category=dict(), # TODO(gfreeman) - Remove this in the next role release. vsys_id=dict(), rulebase=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=False, required_one_of=helper.required_one_of, ) # TODO(gfreeman) - Remove this in the next role release. if not HAS_LIB: module.fail_json(msg='Missing xmltodict library') if module.params['vsys_id'] is not None: module.fail_json(msg='Param "vsys_id" is removed; use vsys') if module.params['rulebase'] is not None: module.deprecate( 'Param "rulebase" is deprecated and may safely be removed from your playbook', version='3.0.0', collection_name='paloaltonetworks.panos') parent = helper.get_pandevice_parent(module) params = ( ('application', 'application', [ 'security', ]), ('category', 'category', [ 'security', ]), ('destination_ip', 'destination', ['security', 'nat']), ('destination_port', 'destination-port', ['security', 'nat']), ('source_zone', 'from', ['security', 'nat']), ('protocol', 'protocol', ['security', 'nat']), ('source_ip', 'source', ['security', 'nat']), ('source_user', 'source-user', [ 'security', ]), ('destination_zone', 'to', ['security', 'nat']), ('to_interface', 'to-interface', [ 'nat', ]), ) cmd = [] rtype = module.params['rule_type'] vsys = module.params['vsys'] # This module used to refreshall on either the security rules or the NAT # rules, however if the rule matched came from Panorama, then this module # failed. To account for this, instead directly query the 3 path locations # where the rule could exist, and return that instead. When pandevice # supports querying the firewall for the pushed down Panorama config, change # this back to using normal pandevice objects. rule_locations = ( ( 'panorama-pre-rulebase', "/config/panorama/vsys/entry[@name='{0}']/pre-rulebase", ), ( 'firewall-rulebase', "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='{0}']/rulebase", ), ( 'panorama-post-rulebase', "/config/panorama/vsys/entry[@name='{0}']/post-rulebase", ), ) suffix = "/{0}/rules/entry[@name='{1}']" if rtype == 'security': cmd.append('test security-policy-match') obj = SecurityRule() else: cmd.append('test nat-policy-match') obj = NatRule() parent.add(obj) for ansible_param, cmd_param, rule_types in params: if rtype not in rule_types or module.params[ansible_param] is None: continue cmd.append('{0} "{1}"'.format(cmd_param, module.params[ansible_param])) # Submit the op command with the appropriate test string test_string = ' '.join(cmd) try: response = helper.device.op(cmd=test_string, vsys=parent.vsys) except PanDeviceError as e: module.fail_json(msg='Failed "{0}": {1}'.format(test_string, e)) elm = response.find('./result/rules/entry') elm2 = response.find('./result/msg/line') if elm is not None: try: rule_name = elm.attrib['name'] except KeyError: rule_name = elm.text elif elm2 is not None: ''' From 8.1 (matching Panorama rule): NOTE: Ending newlines have been truncated to appease codestyle rules. <response cmd="status" status="success"><result><msg><line><![CDATA["Rule Name; index: 1" { from L3-trust; source [ 10.0.0.1 1.1.1.1 ]; source-region none; to L3-untrust; destination [ 8.8.8.8 ]; destination-region none; user any; category any; application/service [0:any/tcp/any/21 1:any/tcp/any/22 ]; action allow; icmp-unreachable: no terminal yes; } ]]></line></msg></result></response> ''' rule_name = elm2.text.split(';')[0].split('"')[1].strip() else: msg = 'No matching {0} rule; resp = {1}'.format( rtype, ET.tostring(response, encoding='utf-8'), ) module.exit_json(msg=msg) ''' Example response (newlines after newlines to appease pycodestyle line length limitations): <response cmd="status" status="success"><result><rules>\n \t<entry>deny all and log; index: 3</entry>\n </rules>\n </result></response> ''' tokens = rule_name.split(';') if len(tokens) == 2 and tokens[1].startswith(' index: '): rule_name = tokens[0] fw = obj.nearest_pandevice() for rulebase, prefix in rule_locations: xpath = prefix.format(vsys) + suffix.format(rtype, rule_name) ans = fw.xapi.get(xpath) if ans is None: continue rules = obj.refreshall_from_xml(ans.find('./result')) if rules: x = rules[0] module.deprecate( 'The "stdout_lines" output is deprecated; use "rule" instead', version='3.0.0', collection_name='paloaltonetworks.panos', ) module.exit_json( stdout_lines=json.dumps(xmltodict.parse(x.element_str()), indent=2), msg='Rule matched', rule=x.about(), rulebase=rulebase, ) module.fail_json( msg='Matched "{0}" with "{1}", but wasn\'t in any rulebase'.format( rule_name, test_string))
def main(): helper = get_connection( with_classic_provider_spec=True, vsys=True, device_group=True, rulebase=True, error_on_firewall_shared=True, argument_spec=dict( rule_name=dict(required=True), description=dict(), nat_type=dict(default='ipv4', choices=['ipv4', 'nat64', 'nptv6']), source_zone=dict(type='list', elements='str'), source_ip=dict(type='list', elements='str', default=['any']), destination_zone=dict(type='str'), destination_ip=dict(type='list', elements='str', default=['any']), to_interface=dict(default='any'), service=dict(default='any'), snat_type=dict(choices=['static-ip', 'dynamic-ip-and-port', 'dynamic-ip']), snat_address_type=dict(choices=['interface-address', 'translated-address'], default='interface-address'), snat_static_address=dict(), snat_dynamic_address=dict(type='list', elements='str'), snat_interface=dict(), snat_interface_address=dict(), snat_bidirectional=dict(type='bool'), dnat_address=dict(), dnat_port=dict(), tag=dict(type='list', elements='str'), state=dict(default='present', choices=['present', 'absent', 'enable', 'disable']), location=dict(choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), commit=dict(type='bool', default=False), # TODO(gfreeman) - remove later. tag_name=dict(), devicegroup=dict(), operation=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=True, required_one_of=helper.required_one_of, ) # TODO(gfreeman) - remove later. if module.params['operation'] is not None: module.fail_json(msg='Param "operation" is removed; use "state"') if module.params['devicegroup'] is not None: module.deprecate( 'Param "devicegroup" is deprecated; use "device_group"', version='3.0.0', collection_name='paloaltonetworks.panos' ) module.params['device_group'] = module.params['devicegroup'] if module.params['tag_name'] is not None: tag_val = module.params['tag_name'] module.deprecate( 'Param "tag_name" is deprecated; use "tag"', version='3.0.0', collection_name='paloaltonetworks.panos' ) if module.params['tag']: module.fail_json(msg='Both "tag" and "tag_name" specified, use only one') else: tag_val = module.params['tag'] parent = helper.get_pandevice_parent(module) # Get object params. rule_name = module.params['rule_name'] description = module.params['description'] source_zone = module.params['source_zone'] source_ip = module.params['source_ip'] destination_zone = module.params['destination_zone'] destination_ip = module.params['destination_ip'] service = module.params['service'] to_interface = module.params['to_interface'] nat_type = module.params['nat_type'] snat_type = module.params['snat_type'] snat_address_type = module.params['snat_address_type'] snat_static_address = module.params['snat_static_address'] snat_dynamic_address = module.params['snat_dynamic_address'] snat_interface = module.params['snat_interface'] snat_interface_address = module.params['snat_interface_address'] snat_bidirectional = module.params['snat_bidirectional'] dnat_address = module.params['dnat_address'] dnat_port = module.params['dnat_port'] # Get other info. state = module.params['state'] location = module.params['location'] existing_rule = module.params['existing_rule'] # Sanity check the location / existing_rule params. if location in ('before', 'after') and not existing_rule: module.fail_json(msg="'existing_rule' must be specified if location is 'before' or 'after'.") # Get the current NAT rules. try: rules = NatRule.refreshall(parent) except PanDeviceError as e: module.fail_json(msg='Failed NAT refreshall: {0}'.format(e)) # Create the desired rule. new_rule = create_nat_rule( rule_name=rule_name, description=description, tag_val=tag_val, source_zone=source_zone, destination_zone=destination_zone, source_ip=source_ip, destination_ip=destination_ip, service=service, to_interface=to_interface, nat_type=nat_type, snat_type=snat_type, snat_address_type=snat_address_type, snat_static_address=snat_static_address, snat_dynamic_address=snat_dynamic_address, snat_interface=snat_interface, snat_interface_address=snat_interface_address, snat_bidirectional=snat_bidirectional, dnat_address=dnat_address, dnat_port=dnat_port ) if not new_rule: module.fail_json(msg='Incorrect NAT rule params specified; quitting') # Perform the desired operation. changed = False diff = None if state in ('enable', 'disable'): for rule in rules: if rule.name == new_rule.name: break else: module.fail_json(msg='Rule "{0}" not present'.format(new_rule.name)) if state == 'enable' and rule.disabled: changed = True elif state == 'disable' and not rule.disabled: changed = True if changed: diff = dict( before=eltostr(rule) ) rule.disabled = not rule.disabled diff['after'] = eltostr(rule) if not module.check_mode: try: rule.update('disabled') except PanDeviceError as e: module.fail_json(msg='Failed enable: {0}'.format(e)) else: parent.add(new_rule) changed, diff = helper.apply_state(new_rule, rules, module) if state == 'present': changed |= helper.apply_position(new_rule, location, existing_rule, module) if changed and module.params['commit']: helper.commit(module) module.exit_json(changed=changed, diff=diff, msg='Done')
def create_nat_rule(**kwargs): nat_rule = NatRule( name=kwargs['rule_name'], description=kwargs['description'], fromzone=kwargs['source_zone'], source=kwargs['source_ip'], tozone=kwargs['destination_zone'], destination=kwargs['destination_ip'], service=kwargs['service'], to_interface=kwargs['to_interface'], nat_type=kwargs['nat_type'] ) # Source translation: Static IP if kwargs['snat_type'] in ['static-ip'] and kwargs['snat_static_address']: nat_rule.source_translation_type = kwargs['snat_type'] nat_rule.source_translation_static_translated_address = kwargs['snat_static_address'] # Bi-directional flag set? if kwargs['snat_bidirectional']: nat_rule.source_translation_static_bi_directional = kwargs['snat_bidirectional'] # Source translation: Dynamic IP and port elif kwargs['snat_type'] in ['dynamic-ip-and-port']: nat_rule.source_translation_type = kwargs['snat_type'] nat_rule.source_translation_address_type = kwargs['snat_address_type'] # Interface address? if kwargs['snat_interface']: nat_rule.source_translation_interface = kwargs['snat_interface'] # Interface IP? if kwargs['snat_interface_address']: nat_rule.source_translation_ip_address = kwargs['snat_interface_address'] else: nat_rule.source_translation_translated_addresses = kwargs['snat_dynamic_address'] # Source translation: Dynamic IP elif kwargs['snat_type'] in ['dynamic-ip']: if kwargs['snat_dynamic_address']: nat_rule.source_translation_type = kwargs['snat_type'] nat_rule.source_translation_translated_addresses = kwargs['snat_dynamic_address'] else: return False # Destination translation if kwargs['dnat_address']: nat_rule.destination_translated_address = kwargs['dnat_address'] if kwargs['dnat_port']: nat_rule.destination_translated_port = kwargs['dnat_port'] # Any tags? if 'tag_val' in kwargs: nat_rule.tag = kwargs['tag_val'] return nat_rule
def main(): helper = get_connection( vsys=True, device_group=True, rulebase=True, with_classic_provider_spec=True, error_on_firewall_shared=True, required_one_of=[ ['listing', 'rule_name', 'rule_regex', 'uuid'], ], argument_spec=dict( listing=dict(type='bool'), rule_name=dict(), rule_regex=dict(), uuid=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=False, required_one_of=helper.required_one_of, ) parent = helper.get_pandevice_parent(module) renames = ( ('name', 'rule_name'), ('fromzone', 'source_zone'), ('tozone', 'destination_zone'), ('source', 'source_ip'), ('destination', 'destination_ip'), ('source_translation_type', 'snat_type'), ('source_translation_static_translated_address', 'snat_static_address'), ('source_translation_static_bi_directional', 'snat_bidirectional'), ('source_translation_address_type', 'snat_address_type'), ('source_translation_interface', 'snat_interface'), ('source_translation_ip_address', 'snat_interface_address'), ('source_translation_translated_addresses', 'snat_dynamic_address'), ('destination_translated_address', 'dnat_address'), ('destination_translated_port', 'dnat_port'), ('tag', 'tag_val'), ) if module.params['rule_name']: obj = NatRule(module.params['rule_name']) parent.add(obj) try: obj.refresh() except PanDeviceError as e: module.fail_json(msg='Failed refresh: {0}'.format(e)) module.exit_json( changed=False, object=helper.to_module_dict(obj, renames), ) try: listing = NatRule.refreshall(parent) except PanDeviceError as e: module.fail_json(msg='Failed refreshall: {0}'.format(e)) if module.params['uuid']: for x in listing: if x.uuid == module.params['uuid']: module.exit_json( changed=False, object=helper.to_module_dict(x, renames), ) module.fail_json( msg='No rule with uuid "{0}"'.format(module.params['uuid'])) ans = [] matcher = None if module.params['rule_regex']: try: matcher = re.compile(module.params['rule_regex']) except Exception as e: module.fail_json(msg='Invalid regex: {0}'.format(e)) ans = [ helper.to_module_dict(x, renames) for x in listing if module.params['listing'] or matcher.search(x.uid) is not None ] module.exit_json(changed=False, listing=ans)
def main(): helper = get_connection( with_classic_provider_spec=True, vsys=True, device_group=True, rulebase=True, error_on_firewall_shared=True, argument_spec=dict( rule_name=dict(required=True), description=dict(), nat_type=dict(default="ipv4", choices=["ipv4", "nat64", "nptv6"]), source_zone=dict(type="list", elements="str"), source_ip=dict(type="list", elements="str", default=["any"]), destination_zone=dict(type="str"), destination_ip=dict(type="list", elements="str", default=["any"]), to_interface=dict(default="any"), service=dict(default="any"), snat_type=dict( choices=["static-ip", "dynamic-ip-and-port", "dynamic-ip"]), snat_address_type=dict( choices=["interface-address", "translated-address"], default="interface-address", ), snat_static_address=dict(), snat_dynamic_address=dict(type="list", elements="str"), snat_interface=dict(), snat_interface_address=dict(), snat_bidirectional=dict(type="bool"), dnat_address=dict(), dnat_port=dict(), tag=dict(type="list", elements="str"), state=dict(default="present", choices=["present", "absent", "enable", "disable"]), location=dict(choices=["top", "bottom", "before", "after"]), existing_rule=dict(), target=dict(type="list", elements="str"), negate_target=dict(type="bool"), commit=dict(type="bool", default=False), # TODO(gfreeman) - remove later. tag_name=dict(), devicegroup=dict(), operation=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=True, required_one_of=helper.required_one_of, ) # TODO(gfreeman) - remove later. if module.params["operation"] is not None: module.fail_json(msg='Param "operation" is removed; use "state"') if module.params["devicegroup"] is not None: module.deprecate( 'Param "devicegroup" is deprecated; use "device_group"', version="3.0.0", collection_name="paloaltonetworks.panos", ) module.params["device_group"] = module.params["devicegroup"] if module.params["tag_name"] is not None: tag_val = module.params["tag_name"] module.deprecate( 'Param "tag_name" is deprecated; use "tag"', version="3.0.0", collection_name="paloaltonetworks.panos", ) if module.params["tag"]: module.fail_json( msg='Both "tag" and "tag_name" specified, use only one') else: tag_val = module.params["tag"] parent = helper.get_pandevice_parent(module) # Get object params. rule_name = module.params["rule_name"] description = module.params["description"] source_zone = module.params["source_zone"] source_ip = module.params["source_ip"] destination_zone = module.params["destination_zone"] destination_ip = module.params["destination_ip"] service = module.params["service"] to_interface = module.params["to_interface"] nat_type = module.params["nat_type"] snat_type = module.params["snat_type"] snat_address_type = module.params["snat_address_type"] snat_static_address = module.params["snat_static_address"] snat_dynamic_address = module.params["snat_dynamic_address"] snat_interface = module.params["snat_interface"] snat_interface_address = module.params["snat_interface_address"] snat_bidirectional = module.params["snat_bidirectional"] dnat_address = module.params["dnat_address"] dnat_port = module.params["dnat_port"] # Get other info. state = module.params["state"] location = module.params["location"] existing_rule = module.params["existing_rule"] target = module.params["target"] negate_target = module.params["negate_target"] # Sanity check the location / existing_rule params. if location in ("before", "after") and not existing_rule: module.fail_json( msg= "'existing_rule' must be specified if location is 'before' or 'after'." ) # Get the current NAT rules. try: rules = NatRule.refreshall(parent) except PanDeviceError as e: module.fail_json(msg="Failed NAT refreshall: {0}".format(e)) # Create the desired rule. new_rule = create_nat_rule( rule_name=rule_name, description=description, tag_val=tag_val, source_zone=source_zone, destination_zone=destination_zone, source_ip=source_ip, destination_ip=destination_ip, service=service, to_interface=to_interface, nat_type=nat_type, snat_type=snat_type, snat_address_type=snat_address_type, snat_static_address=snat_static_address, snat_dynamic_address=snat_dynamic_address, snat_interface=snat_interface, snat_interface_address=snat_interface_address, snat_bidirectional=snat_bidirectional, dnat_address=dnat_address, dnat_port=dnat_port, target=target, negate_target=negate_target, ) if not new_rule: module.fail_json(msg="Incorrect NAT rule params specified; quitting") # Perform the desired operation. changed = False diff = None if state in ("enable", "disable"): for rule in rules: if rule.name == new_rule.name: break else: module.fail_json( msg='Rule "{0}" not present'.format(new_rule.name)) if state == "enable" and rule.disabled: changed = True elif state == "disable" and not rule.disabled: changed = True if changed: diff = dict(before=eltostr(rule)) rule.disabled = not rule.disabled diff["after"] = eltostr(rule) if not module.check_mode: try: rule.update("disabled") except PanDeviceError as e: module.fail_json(msg="Failed enable: {0}".format(e)) else: parent.add(new_rule) changed, diff = helper.apply_state(new_rule, rules, module) if state == "present": changed |= helper.apply_position(new_rule, location, existing_rule, module) if changed and module.params["commit"]: helper.commit(module) module.exit_json(changed=changed, diff=diff, msg="Done")
def create_nat_rule(**kwargs): nat_rule = NatRule( name=kwargs["rule_name"], description=kwargs["description"], fromzone=kwargs["source_zone"], source=kwargs["source_ip"], tozone=kwargs["destination_zone"], destination=kwargs["destination_ip"], service=kwargs["service"], to_interface=kwargs["to_interface"], nat_type=kwargs["nat_type"], ) # Source translation: Static IP if kwargs["snat_type"] in ["static-ip"] and kwargs["snat_static_address"]: nat_rule.source_translation_type = kwargs["snat_type"] nat_rule.source_translation_static_translated_address = kwargs[ "snat_static_address"] # Bi-directional flag set? if kwargs["snat_bidirectional"]: nat_rule.source_translation_static_bi_directional = kwargs[ "snat_bidirectional"] # Source translation: Dynamic IP and port elif kwargs["snat_type"] in ["dynamic-ip-and-port"]: nat_rule.source_translation_type = kwargs["snat_type"] nat_rule.source_translation_address_type = kwargs["snat_address_type"] # Interface address? if kwargs["snat_interface"]: nat_rule.source_translation_interface = kwargs["snat_interface"] # Interface IP? if kwargs["snat_interface_address"]: nat_rule.source_translation_ip_address = kwargs[ "snat_interface_address"] else: nat_rule.source_translation_translated_addresses = kwargs[ "snat_dynamic_address"] # Source translation: Dynamic IP elif kwargs["snat_type"] in ["dynamic-ip"]: if kwargs["snat_dynamic_address"]: nat_rule.source_translation_type = kwargs["snat_type"] nat_rule.source_translation_translated_addresses = kwargs[ "snat_dynamic_address"] else: return False # Destination translation if kwargs["dnat_address"]: nat_rule.destination_translated_address = kwargs["dnat_address"] if kwargs["dnat_port"]: nat_rule.destination_translated_port = kwargs["dnat_port"] # Any tags? if "tag_val" in kwargs: nat_rule.tag = kwargs["tag_val"] nat_rule.target = kwargs["target"] nat_rule.negate_target = kwargs["negate_target"] return nat_rule