def run(self, class_string, device_group, firewall, objects, pre_rulebase): device = self.get_panorama(firewall, device_group) pandevice_class = self.get_pandevice_class(class_string) cls = pandevice_class['cls'] # we need some special logic for policies if device_group and pre_rulebase: rulebase = PreRulebase() elif device_group and not pre_rulebase: rulebase = PostRulebase() else: rulebase = Rulebase() device.add(rulebase) # because we are deleting in bulk, we do not refresh the object tree for obj in objects: if not isinstance(obj, str): raise ValueError("{} is not a valid {} object name!".format( obj, cls.__name__)) pandevice_object = cls(name=obj) rulebase.add(pandevice_object) pandevice_object.delete_similar() device_value = device_group or firewall return True, "{} objects successfully deleted from {}".format( cls.__name__, device_value)
def run(self, class_string, device_group, firewall, objects, pre_rulebase): device = self.get_panorama(firewall, device_group) pandevice_class = self.get_pandevice_class(class_string) cls = pandevice_class['cls'] # we need some special logic for policies if device_group and pre_rulebase: rulebase = PreRulebase() elif device_group and not pre_rulebase: rulebase = PostRulebase() else: rulebase = Rulebase() device.add(rulebase) cls.refreshall(parent=rulebase) for obj in objects: if not isinstance(obj, dict): raise ValueError("{} is not a valid {} object!".format( obj, cls.__name__)) if not set(obj.keys()).issubset(set( pandevice_class['valid_keys'])): raise ValueError( "{} contains invalid values for a {} object!".format( obj, cls.__name__)) # manually update an existing object or add a new one pandevice_object = rulebase.find(obj['name'], class_type=cls) if pandevice_object is not None: for key, value in obj.items(): setattr(pandevice_object, key, value) else: pandevice_object = cls(**obj) rulebase.add(pandevice_object) pandevice_object.apply_similar() device_value = device_group or firewall return True, "{} objects successfully applied to {}".format( cls.__name__, device_value)
def run(self, class_string, device_group, firewall, pre_rulebase, **kwargs): device = self.get_panorama(firewall, device_group) pandevice_class = self.get_pandevice_class(class_string) cls = pandevice_class['cls'] obj = cls(**kwargs) # we need some special logic for policies if device_group and pre_rulebase: rulebase = PreRulebase() elif device_group and not pre_rulebase: rulebase = PostRulebase() else: rulebase = Rulebase() device.add(rulebase) rulebase.add(obj) obj.delete() device_value = device_group or firewall return True, "{} {} successfully deleted from {}".format( cls.__name__, obj.name, device_value)
def get_pandevice_parent(self, module, timeout=0): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. * timeout(int): Number of seconds to retry opening the connection to PAN-OS. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') # Verify pandevice minimum version. if self.min_pandevice_version is not None: pdv = tuple(int(x) for x in pandevice.__version__.split('.')) if pdv < self.min_pandevice_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'pandevice', pandevice.__version__, _vstr(self.min_pandevice_version))) pan_device_auth, serial_number = None, None if module.params['provider'] and module.params['provider'][ 'ip_address']: pan_device_auth = ( module.params['provider']['ip_address'], module.params['provider']['username'], module.params['provider']['password'], module.params['provider']['api_key'], module.params['provider']['port'], ) serial_number = module.params['provider']['serial_number'] elif module.params.get('ip_address', None) is not None: pan_device_auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], module.params['port'], ) msg = 'Classic provider params are deprecated; use "provider" instead' module.deprecate(msg, '2.12') else: module.fail_json(msg='Provider params are required.') # Create the connection object. if not isinstance(timeout, int): raise ValueError('Timeout must be an int') elif timeout < 0: raise ValueError('Timeout must greater than or equal to 0') end_time = time.time() + timeout while True: try: self.device = PanDevice.create_from_device(*pan_device_auth) except PanDeviceError as e: if timeout == 0: module.fail_json(msg='Failed connection: {0}'.format(e)) elif time.time() >= end_time: module.fail_json(msg='Connection timeout: {0}'.format(e)) else: break # Verify PAN-OS minimum version. if self.min_panos_version is not None: if self.device._version_info < self.min_panos_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'PAN-OS', _vstr(self.device._version_info), _vstr(self.min_panos_version))) # Optional: Firewall via Panorama connectivity specified. if hasattr(self.device, 'refresh_devices') and serial_number: fw = Firewall(serial=serial_number) self.device.add(fw) self.device = fw parent = self.device no_shared = 'Scope "shared" is not allowed' not_found = '{0} "{1}" is not present.' pano_mia_param = 'Param "{0}" is required for Panorama but not specified.' ts_error = 'Specify either the template or the template stack{0}.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. templated = False # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. tmpl_required = False added_template = False if self.template_stack is not None: name = module.params[self.template_stack] if name is not None: templated = True stacks = TemplateStack.refreshall(parent, name_only=True) for ts in stacks: if ts.name == name: parent = ts added_template = True break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) elif self.template is not None: tmpl_required = True else: module.fail_json( msg=pano_mia_param.format(self.template_stack)) # Spec: template. if self.template is not None: name = module.params[self.template] if name is not None: templated = True if added_template: module.fail_json(msg=ts_error.format(', not both')) templates = Template.refreshall(parent, name_only=True) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) elif tmpl_required: module.fail_json(msg=ts_error.format('')) elif not added_template: module.fail_json(msg=pano_mia_param.format(self.template)) # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent, name_only=True) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) elif self.error_on_shared: module.fail_json(msg=no_shared) # Spec: vsys importable. vsys_name = self.vsys_importable or self.vsys or self.vsys_shared if dg_name is None and templated and vsys_name is not None: name = module.params[vsys_name] if name not in (None, 'shared'): vo = Vsys(name) parent.add(vo) parent = vo # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'rulebase': rb = Rulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable or self.vsys_shared if vsys_name is not None: parent.vsys = module.params[vsys_name] if parent.vsys == 'shared' and self.error_on_shared: module.fail_json(msg=no_shared) # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def main(): argument_spec = dict( ip_address=dict(required=True), username=dict(default='admin'), password=dict(required=True, no_log=True), api_key=dict(no_log=True), operation=dict(choices=['add', 'update', 'delete', 'find', 'disable']), state=dict(default='present', choices=['present', 'absent']), rule_name=dict(required=True), description=dict(), nat_type=dict(default='ipv4', choices=['ipv4', 'nat64', 'nptv6']), tag_name=dict(), source_zone=dict(type='list'), source_ip=dict(type='list', default=['any']), destination_zone=dict(), destination_ip=dict(type='list', default=['any']), service=dict(default='any'), to_interface=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'), snat_interface=dict(), snat_interface_address=dict(), snat_bidirectional=dict(type='bool', default=False), dnat_address=dict(), dnat_port=dict(), devicegroup=dict(default='shared'), rulebase=dict(default='pre-rulebase', choices=['pre-rulebase', 'post-rulebase']), vsys=dict(default='vsys1'), location=dict(default='bottom', choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), commit=dict(type='bool', default=True)) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') elif not hasattr(NatRule, 'move'): module.fail_json(msg='Python library pandevice needs to be updated.') # Get firewall / Panorama auth. auth = [ module.params[x] for x in ('ip_address', 'username', 'password', 'api_key') ] # Get object params. rule_name = module.params['rule_name'] description = module.params['description'] tag_name = module.params['tag_name'] 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. operation = module.params['operation'] state = module.params['state'] devicegroup = module.params['devicegroup'] vsys = module.params['vsys'] commit = module.params['commit'] 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'." ) # Create the device with the appropriate pandevice type con = PanDevice.create_from_device(*auth) # Set vsys if firewall, device group if Panorama, and set the rulebase. parent = con if hasattr(con, 'refresh_devices'): # Panorama if devicegroup not in (None, 'shared'): dev_group = get_devicegroup(con, devicegroup) if not dev_group: module.fail_json( msg= '\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) parent = dev_group if module.params['rulebase'] in (None, 'pre-rulebase'): rulebase = PreRulebase() parent.add(rulebase) parent = rulebase elif module.params['rulebase'] == 'post-rulebase': rulebase = PostRulebase() parent.add(rulebase) parent = rulebase else: # Firewall parent.vsys = vsys rulebase = Rulebase() parent.add(rulebase) parent = rulebase # 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_name=tag_name, 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') parent.add(new_rule) # Perform the desired operation. changed = False do_move = False if state == 'present': match = find_rule(rules, new_rule) if match is not None: if not match.equal(new_rule): try: new_rule.apply() except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: changed = True do_move = True else: try: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "present" create: {0}'.format(e)) else: changed = True do_move = True elif state == 'absent': match = find_rule(rules, new_rule) if match is not None: try: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) else: changed = True elif operation == "find": # Search for the rule match = find_rule(rules, new_rule) # If found, format and return the result if match: match_dict = xmltodict.parse(match.element_str()) module.exit_json(stdout_lines=json.dumps(match_dict, indent=2), msg='Rule matched') else: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % rule_name) elif operation == "delete": # Search for the object match = find_rule(rules, new_rule) if match is None: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % rule_name) try: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "delete" delete: {0}'.format(e)) else: changed = True elif operation == "add": # Look for required parameters if not source_zone or not destination_zone or not nat_type: module.fail_json( msg= 'Missing parameter. Required: source_zone, destination_zone, nat_type' ) # Search for the rule. Fail if found. match = find_rule(rules, new_rule) if match: module.fail_json( msg= 'Rule \'%s\' already exists. Use operation: \'update\' to change it.' % rule_name) try: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "add" create: {0}'.format(e)) else: changed = True do_move = True elif operation == 'update': # Search for the rule. Update if found. match = find_rule(rulebase, rule_name) if not match: module.fail_json( msg= 'Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % rule_name) try: new_rule.apply() except PanDeviceError as e: module.fail_json(msg='Failed "update" apply: {0}'.format(e)) else: changed = True do_move = True elif operation == 'disable': # Search for the rule, disable if found. match = find_rule(rules, new_rule) if not match: module.fail_json(msg='Rule \'%s\' does not exist.' % rule_name) if not match.disabled: match.disabled = True try: match.update('disabled') except PanDeviceError as e: module.fail_json(msg='Failed "disabled": {0}'.format(e)) else: changed = True # Optional move. if do_move: try: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) else: changed = True # Optional commit. if changed and commit: try: con.commit(sync=True) except PanDeviceError as e: module.fail_json(msg='Failed commit: {0}'.format(e)) module.exit_json(changed=changed, msg='Done')
def main(): argument_spec = dict( ip_address=dict(required=True), username=dict(default='admin'), password=dict(no_log=True), api_key=dict(no_log=True), rule_name=dict(required=True), source_zone=dict(type='list', default=['any']), source_ip=dict(type='list', default=["any"]), source_user=dict(type='list', default=['any']), hip_profiles=dict(type='list', default=['any']), destination_zone=dict(type='list', default=['any']), destination_ip=dict(type='list', default=["any"]), application=dict(type='list', default=['any']), service=dict(type='list', default=['application-default']), category=dict(type='list', default=['any']), action=dict(default='allow', choices=[ 'allow', 'deny', 'drop', 'reset-client', 'reset-server', 'reset-both' ]), log_setting=dict(), log_start=dict(type='bool', default=False), log_end=dict(type='bool', default=True), description=dict(default=''), rule_type=dict(default='universal', choices=['universal', 'intrazone', 'interzone']), tag_name=dict(type='list'), negate_source=dict(type='bool', default=False), negate_destination=dict(type='bool', default=False), disabled=dict(type='bool', default=False), schedule=dict(), icmp_unreachable=dict(type='bool'), disable_server_response_inspection=dict(type='bool', default=False), group_profile=dict(), antivirus=dict(), spyware=dict(), vulnerability=dict(), url_filtering=dict(), file_blocking=dict(), wildfire_analysis=dict(), data_filtering=dict(), target=dict(type='list'), negate_target=dict(type='bool', default=False), location=dict(choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), devicegroup=dict(), rulebase=dict(default='pre-rulebase', choices=['pre-rulebase', 'post-rulebase']), vsys=dict(default='vsys1'), state=dict(choices=['present', 'absent']), operation=dict(default='add', choices=['add', 'update', 'delete', 'find']), commit=dict(type='bool', default=True)) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') elif not hasattr(SecurityRule, 'move'): module.fail_json(msg='Python library pandevice needs to be updated.') # Get the firewall / panorama auth. auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], ) # Set the SecurityRule object params rule_spec = { 'name': module.params['rule_name'], 'fromzone': module.params['source_zone'], 'tozone': module.params['destination_zone'], 'source': module.params['source_ip'], 'source_user': module.params['source_user'], 'hip_profiles': module.params['hip_profiles'], 'destination': module.params['destination_ip'], 'application': module.params['application'], 'service': module.params['service'], 'category': module.params['category'], 'action': module.params['action'], 'log_setting': module.params['log_setting'], 'log_start': module.params['log_start'], 'log_end': module.params['log_end'], 'description': module.params['description'], 'type': module.params['rule_type'], 'tag': module.params['tag_name'], 'negate_source': module.params['negate_source'], 'negate_destination': module.params['negate_destination'], 'disabled': module.params['disabled'], 'schedule': module.params['schedule'], 'icmp_unreachable': module.params['icmp_unreachable'], 'disable_server_response_inspection': module.params['disable_server_response_inspection'], 'group': module.params['group_profile'], 'virus': module.params['antivirus'], 'spyware': module.params['spyware'], 'vulnerability': module.params['vulnerability'], 'url_filtering': module.params['url_filtering'], 'file_blocking': module.params['file_blocking'], 'wildfire_analysis': module.params['wildfire_analysis'], 'data_filtering': module.params['data_filtering'], } # Get other info location = module.params['location'] existing_rule = module.params['existing_rule'] devicegroup = module.params['devicegroup'] rulebase = module.params['rulebase'] vsys = module.params['vsys'] state = module.params['state'] operation = module.params['operation'] commit = module.params['commit'] # 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'." ) # Open the connection to the PAN-OS device device = None try: device = PanDevice.create_from_device(*auth) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Add some additional rule params if device is Panorama if isinstance(device, Panorama): rule_spec['target'] = module.params['target'] rule_spec['negate_target'] = module.params['negate_target'] # Set the attachment point for the RuleBase object parent = device if isinstance(parent, Firewall): if vsys is not None: vsys_list = Vsys.refreshall(parent) parent = get_vsys(vsys, vsys_list) if parent is None: module.fail_json(msg='VSYS not found: {0}'.format(vsys)) parent = parent.add(Rulebase()) elif isinstance(parent, Panorama): if devicegroup == 'shared': devicegroup = None if devicegroup is not None: parent = parent.add(Rulebase()) else: parent = get_devicegroup(parent, devicegroup) if parent is None: module.fail_json( msg='Device group not found: {0}'.format(devicegroup)) if rulebase == 'pre-rulebase': parent = parent.add(PreRulebase()) elif rulebase == 'post-rulebase': parent = parent.add(PostRulebase()) # Now that we have the rulebase let's grab its security rules rules = SecurityRule.refreshall(parent) # Create new rule object from the params and add to rulebase new_rule = SecurityRule(**rule_spec) parent.add(new_rule) # Which action shall we take on the rule object? changed = False if state == 'present': match = find_rule(rules, new_rule) if match: # Change an existing rule if not match.equal(new_rule): try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: changed = True else: # Add a new rule try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "present" apply: {0}'.format(e)) else: changed = True # Move the rule if location is defined if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) else: changed = True elif state == 'absent': match = find_rule(rules, new_rule) if match: # Delete an existing rule try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) else: changed = True elif operation == "find": # Search for the rule match = find_rule(rules, new_rule) # If found, format and return the result if match: module.exit_json(stdout_lines=match.about(), msg='Rule matched') else: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) elif operation == "delete": # Search for the object match = find_rule(rules, new_rule) if match is None: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "delete" delete: {0}'.format(e)) else: changed = True elif operation == "add": # Search for the rule. Fail if found. match = find_rule(rules, new_rule) if match: module.fail_json( msg= 'Rule \'%s\' already exists. Use operation: \'update\' to change it.' % new_rule.name) try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "add" create: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) elif operation == 'update': # Search for the rule. Update if found. match = find_rule(rulebase, new_rule.name) if not match: module.fail_json( msg= 'Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % new_rule.name) try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json(msg='Failed "update" apply: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) # Optional commit. # FIXME: Commits should be done using the separate commit module if changed and commit: try: device.commit(sync=True) except PanDeviceError as e: module.fail_json(msg='Failed commit: {0}'.format(e)) module.exit_json(changed=changed, msg='Done')
def get_pandevice_parent(self, module): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') d, host_arg = None, None if module.params['provider'] and module.params['provider']['host']: d = module.params['provider'] host_arg = 'host' elif module.params['ip_address'] is not None: d = module.params host_arg = 'ip_address' else: module.fail_json(msg='New or classic provider params are required.') # Create the connection object. try: self.device = PanDevice.create_from_device( d[host_arg], d['username'], d['password'], d['api_key']) except PanDeviceError as e: module.fail_json(msg='Failed connection: {0}'.format(e)) parent = self.device not_found = '{0} "{1}" is not present.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. if self.template_stack is not None: name = module.params[self.template_stack] stacks = TemplateStack.refreshall(parent) for ts in stacks: if ts.name == name: parent = ts break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) # Spec: template. if self.template is not None: name = module.params[self.template] templates = Template.refreshall(parent) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) # Spec: vsys importable. if self.vsys_importable is not None: name = module.params[self.vsys_importable] if name is not None: vo = Vsys(name) parent.add(vo) parent = vo # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable if vsys_name is not None: self.con.vsys = module.params[vsys_name] # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def main(): parser = argparse.ArgumentParser() parser.add_argument('--panorama', help='hostname or ip of panorama', required=True) parser.add_argument( '--master_device', help='hostname or ip of firewall to retrieve group-mappings', required=True) parser.add_argument( '--dg', help= 'device group of the pre-rulebase that contain user-group-based policies', required=True) args = parser.parse_args() try: panorama = Panorama(args.panorama, input('Panorama username: '******'Panorama password: '******'show devices connected' try: res = panorama.op(cmd, xml=True) except PanDeviceError as e: print(e.message) sys.exit(1) devs_connected = xmltodict.parse( res)['response']['result']['devices']['entry'] firewall = None for dev in devs_connected: if dev['hostname'] == args.master_device or dev[ 'ip-address'] == args.master_device: firewall = Firewall(serial=dev['serial']) break if firewall is not None: try: panorama.add(firewall) except PanDeviceError as e: print(e.message) else: print( 'Master device (firewall) is not managed by Panorama. Attempting direct connection to firewall...' ) try: firewall = Firewall(args.master_device, input('Firewall username: '******'Firewall password: '******'Retrieving user-group-mappings on master device: "{}"...'.format( args.master_device)) cmd = 'show user group list' try: res = firewall.op(cmd, xml=True) except PanDeviceError as e: print(e.message) user_group_data = xmltodict.parse(res)['response']['result'] user_group_list = re.findall(r'cn=.*?dc=com', user_group_data) print('Number of mapped user-groups found: {}\n'.format( len(user_group_list))) print('Currently mapped user-groups: ') for user_group in user_group_list: print('"{}"'.format(user_group)) print('\n') try: DeviceGroup.refreshall(panorama) target_dg = panorama.find(args.dg, DeviceGroup) if target_dg is None: print( 'Device group "{}" not found on Panorama device. Aborting...'. format(args.dg)) sys.exit() prb = PreRulebase() target_dg.add(prb) dg_pre_rules = SecurityRule.refreshall(prb) except PanDeviceError as e: print(e.message) print('Retrieving user-based security policy from device-group: "{}"...'. format(args.dg)) user_based_rules = [] for rule in dg_pre_rules: if not 'any' in rule.source_user: user_based_rules.append(rule) print('Number of user-based security rules found: {}\n'.format( len(user_based_rules))) for rule in user_based_rules: print('Validating user-based security rule: "{}"...'.format(rule.name)) for user in rule.source_user: if not user in user_group_list: print('Invalid user-group: "{}"'.format(user)) print('\n')
def get_pandevice_parent(self, module): """Builds the pandevice object tree, returning the parent object. If pandevice is not installed, then module.fail_json() will be invoked. Arguments: * module(AnsibleModule): the ansible module. Returns: * The parent pandevice object based on the spec given to get_connection(). """ # Sanity check. if not HAS_PANDEVICE: module.fail_json(msg='Missing required library "pandevice".') # Verify pandevice minimum version. if self.min_pandevice_version is not None: pdv = tuple(int(x) for x in pandevice.__version__.split('.')) if pdv < self.min_pandevice_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'pandevice', pandevice.__version__, _vstr(self.min_pandevice_version))) d, host_arg = None, None if module.params['provider'] and module.params['provider']['host']: d = module.params['provider'] host_arg = 'host' elif module.params['ip_address'] is not None: d = module.params host_arg = 'ip_address' else: module.fail_json( msg='New or classic provider params are required.') # Create the connection object. try: self.device = PanDevice.create_from_device(d[host_arg], d['username'], d['password'], d['api_key'], d['port']) except PanDeviceError as e: module.fail_json(msg='Failed connection: {0}'.format(e)) # Verify PAN-OS minimum version. if self.min_panos_version is not None: if self.device._version_info < self.min_panos_version: module.fail_json(msg=_MIN_VERSION_ERROR.format( 'PAN-OS', _vstr(self.device._version_info), _vstr(self.min_panos_version))) parent = self.device not_found = '{0} "{1}" is not present.' pano_mia_param = 'Param "{0}" is required for Panorama but not specified.' ts_error = 'Specify either the template or the template stack{0}.' if hasattr(self.device, 'refresh_devices'): # Panorama connection. # Error if Panorama is not supported. if self.panorama_error is not None: module.fail_json(msg=self.panorama_error) # Spec: template stack. tmpl_required = False added_template = False if self.template_stack is not None: name = module.params[self.template_stack] if name is not None: stacks = TemplateStack.refreshall(parent, name_only=True) for ts in stacks: if ts.name == name: parent = ts added_template = True break else: module.fail_json(msg=not_found.format( 'Template stack', name, )) elif self.template is not None: tmpl_required = True else: module.fail_json( msg=pano_mia_param.format(self.template_stack)) # Spec: template. if self.template is not None: name = module.params[self.template] if name is not None: if added_template: module.fail_json(msg=ts_error.format(', not both')) templates = Template.refreshall(parent, name_only=True) for t in templates: if t.name == name: parent = t break else: module.fail_json(msg=not_found.format( 'Template', name, )) elif tmpl_required: module.fail_json(msg=ts_error.format('')) else: module.fail_json(msg=pano_mia_param.format(self.template)) # Spec: vsys importable. vsys_name = self.vsys_importable or self.vsys if vsys_name is not None: name = module.params[vsys_name] if name not in (None, 'shared'): vo = Vsys(name) parent.add(vo) parent = vo # Spec: vsys_dg or device_group. dg_name = self.vsys_dg or self.device_group if dg_name is not None: name = module.params[dg_name] if name not in (None, 'shared'): groups = DeviceGroup.refreshall(parent, name_only=True) for dg in groups: if dg.name == name: parent = dg break else: module.fail_json(msg=not_found.format( 'Device group', name, )) # Spec: rulebase. if self.rulebase is not None: if module.params[self.rulebase] in (None, 'pre-rulebase'): rb = PreRulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'rulebase': rb = Rulebase() parent.add(rb) parent = rb elif module.params[self.rulebase] == 'post-rulebase': rb = PostRulebase() parent.add(rb) parent = rb else: module.fail_json(msg=not_found.format( 'Rulebase', module.params[self.rulebase])) else: # Firewall connection. # Error if firewalls are not supported. if self.firewall_error is not None: module.fail_json(msg=self.firewall_error) # Spec: vsys or vsys_dg or vsys_importable. vsys_name = self.vsys_dg or self.vsys or self.vsys_importable if vsys_name is not None: self.device.vsys = module.params[vsys_name] # Spec: rulebase. if self.rulebase is not None: rb = Rulebase() parent.add(rb) parent = rb # Done. return parent
def main(): parser = argparse.ArgumentParser() parser.add_argument('--panorama', help='hostname or ip of panorama', required=True) parser.add_argument('--user', help='username for auth to panorama', required=True) parser.add_argument( '--dg', help= 'device group of the pre-rulebase that contain user-group-based policies', required=True) parser.add_argument('--group_mapping', help='legacy to PAN LDAP group mappings csv file', required=True) args = parser.parse_args() try: panorama = Panorama(args.panorama, args.user, getpass()) except PanDeviceError as e: print(e.message) print('Retrieving user-based security policy from device-group: "{}"...'. format(args.dg)) try: DeviceGroup.refreshall(panorama) target_dg = panorama.find(args.dg, DeviceGroup) if target_dg is None: print( 'Device group "{}" not found on Panorama device. Aborting...'. format(args.dg)) sys.exit() prb = PreRulebase() target_dg.add(prb) dg_pre_rules = SecurityRule.refreshall(prb) except PanDeviceError as e: print(e.message) with open(args.group_mapping, newline='') as csvfile: reader = csv.reader(csvfile) group_map_dict = {} for row in reader: group_map_dict[row[0]] = row[1] changed = None for rule in dg_pre_rules: if not 'any' in rule.source_user: print(rule.name) for k, v in group_map_dict.items(): for user in rule.source_user: if user == k: print('{0} -> {1}'.format(user, v)) if not v in rule.source_user: rule.source_user.append(v) rule.source_user.remove(k) changed = True if changed: try: rule.apply() changed = False except PanDeviceError as e: print(e.message)