def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) changed = False engine = self.fetch_element(Engine) if state == 'present': if not engine: # Find interface designated as management if not self.interfaces: self.fail(msg='You must provide at least one interface ' 'configuration to create a firewall.') if not self.primary_mgt: self.fail( msg='You must provide a primary_mgt interface to create ' 'an engine.') if not self.type: self.fail( msg='You must specify an engine by type when creating a ' 'new engine. Types: %s' % engine_types()) if 'fw_cluster' in self.type and not self.cluster_mode: self.fail( msg='You must define a cluster mode to create an engine' ) itf = self.check_interfaces() # Management interface if not self.primary_mgt in itf: self.fail( msg= 'Management interface is not defined. Management was ' 'specified on interface: %s' % self.primary_mgt) else: self.type = engine.type if self.interfaces and not self.skip_interfaces: itf = self.check_interfaces() else: itf = [] cache = Cache() # SNMP settings if self.snmp and self.snmp.get('enabled', True): cache._add_entry('snmp_agent', self.snmp.get('snmp_agent', None)) if cache.missing: self.fail( msg= 'SNMP configured but the SNMP Agent specified is not ' 'found: %s' % cache.missing) # Only validate BGP if it's specifically set to enabled if self.bgp and self.bgp.get('enabled', True): # BGP Profile if specified if self.bgp.get('bgp_profile', None): cache._add_entry('bgp_profile', self.bgp['bgp_profile']) if cache.missing: self.fail( msg= 'A BGP Profile was specified that does not exist: ' '%s' % self.bgp['bgp_profile']) # Get external bgp peers, can be type 'engine' or 'external_bgp_peer' # Can also be empty if you don't want to attach a peer. peerings = self.bgp.get('bgp_peering', []) for peer in peerings: if 'name' not in peer or 'interface_id' not in peer: self.fail( msg= 'BGP Peering requires a name and interface_id for the ' 'BGP Peering element. Info provided: %s' % peer) # The specified interface ID must exist for the BGP Peering to succeed. If # the interface is defined in yaml, we'll assume it will be created. If the # engine exists, check if it's defined or if it already exists peer_id = str(peer['interface_id']) if peer_id not in itf and not engine: self.fail( msg= 'Interface ID: %s specified for BGP Peering does not ' 'exist. You must specify a valid interface to bind the peer ' % peer_id) elif engine and (peer_id not in engine.interface and peer_id not in itf): self.fail( msg= 'BGP Peering interface id: %s specified does not exist ' 'on the current engine: %s' % (peer_id, engine.name)) if 'external_bgp_peer' not in peer and 'engine' not in peer: self.fail( msg= 'Missing the external_bgp_peer or engine parameter ' 'which defines the next hop for the BGP Peering') if 'external_bgp_peer' in peer: cache._add_entry('external_bgp_peer', peer['external_bgp_peer']) elif 'engine' in peer: cache._add_entry('fw_cluster', peer['engine']) if cache.missing: self.fail(msg='Missing external BGP Peering elements: %s' % cache.missing) as_system = self.bgp.get('autonomous_system', {}) if not engine: # We are trying to enable BGP on a new engine, Autonomous System # is required if not as_system: self.fail( msg= 'You must specify an Autonomous System when enabling ' 'BGP on a newly created engine.') if as_system: if 'name' not in as_system or 'as_number' not in as_system: self.fail( msg='Autonomous System requires a name and and ' 'as_number value.') spoofing = self.bgp.get('antispoofing_network', {}) self.validate_antispoofing_network(spoofing) cache.add(spoofing) if cache.missing: self.fail( msg='Missing elements in antispoofing configuration: %s' % cache.missing) networks = self.bgp.get('announced_network', []) announced_networks = self.validate_and_extract_announced( networks) cache.add(announced_networks) if cache.missing: self.fail( msg='Missing elements in announced configuration: %s' % cache.missing) if self.netlinks: # Netlinks can be specified on an interface along with destination elements # 'behind' these netlinks. Netlinks can only be placed on physical interface # types and not tunnel interfaces for netlink in self.netlinks: if 'name' not in netlink or 'interface_id' not in netlink: self.fail( msg= 'Netlink requires a name and interface_id for the ' 'Netlink element. Info provided: %s' % netlink) int_id = str(netlink['interface_id']) if int_id not in itf and not engine: self.fail( msg= 'Interface ID: %s specified for netlink does not ' 'exist. You must specify a valid interface to bind the netlink' % int_id) elif engine and (int_id not in engine.physical_interface and int_id not in itf): self.fail( msg= 'Netlink interface id: %s specified does not exist ' 'on the current engine: %s' % (int_id, engine.name)) # Get required elements specified for configuration cache._add_entry('netlink', netlink['name']) # Destination elements for netlink are optional if netlink.get('destination', []) and isinstance( netlink['destination'], list): for dest in netlink['destination']: if 'name' not in dest or 'type' not in dest: self.fail( msg= 'Netlink destination element reference must ' 'contain name and type key values. Provided: %s' % dest) cache._add_entry(dest['type'], dest['name']) if cache.missing: self.fail( msg='Missing elements in netlink configuration: %s' % cache.missing) self.cache = cache try: if state == 'present': if not engine: interfaces = [vars(intf) for intf in itf] firewall = {'interfaces': interfaces} firewall.update( name=self.name, primary_mgt=self.primary_mgt, backup_mgt=self.backup_mgt, log_server_ref=self.log_server, domain_server_address=self.domain_server_address, default_nat=self.default_nat, enable_antivirus=self.antivirus, enable_gti=self.file_reputation, location_ref=self.location, snmp=self.snmp, comment=self.comment) if self.check_mode: return self.results if 'fw_cluster' in self.type: firewall.update( cluster_mode=self.cluster_mode, primary_heartbeat=self.primary_heartbeat) engine = FirewallCluster.create_bulk(**firewall) else: engine = Layer3Firewall.create_bulk(**firewall) self.results['state'].append({ 'name': engine.name, 'type': engine.type, 'action': 'created' }) changed = True else: # Engine exists, check for modifications # Changes made up to check mode are done on the # cached instance of the engine and not sent to SMC if self.update_general(engine): changed = True if self.update_snmp(engine): changed = True if 'fw_cluster' in self.type and \ (self.cluster_mode and engine.cluster_mode != self.cluster_mode): engine.data.update(cluster_mode=self.cluster_mode) changed = True if self.check_mode: return self.results # Check engine location value if self.update_location(engine): changed = True # First actual engine update happens here if changed: engine.update() # Reset management interfaces before operating on interfaces # in case interfaces are removed that might have previously # been used as interface options (primary mgt, etc) if self.reset_management(engine): changed = True # Set skip interfaces to bypass interface checks if not self.skip_interfaces: self.update_interfaces(engine) # Lastly, delete top level interfaces that are not defined in # the YAML or added while looping. Only delete if skip_interfaces # was not provided and that delete_undefined_interfaces is set to True if not self.skip_interfaces and self.delete_undefined_interfaces: self.check_for_deletes(engine) ###### # Check for BGP configuration on either newly created engine # or on the existing ###### if self.bgp: bgp = engine.bgp enabled = self.bgp.get('enabled', True) if not enabled and bgp.status: bgp.disable() changed = True elif enabled: if self.update_bgp(bgp): autonomous_system, created = get_or_create_asystem( self.bgp.get('autonomous_system')) if created: changed = True bgp.disable() # Reset BGP configuration bgp.enable(autonomous_system, announced_networks=[], antispoofing_networks=self. antispoofing_format(), router_id=self.bgp.get('router_id', ''), bgp_profile=self.cache.get( 'bgp_profile', self.bgp.get('bgp_profile', None))) for network in self.announced_network_format(): bgp.advertise_network(**network) changed = True if changed: engine.update() if enabled: # BGP Peering is last since the BGP configuration may be placed # on interfaces that might have been modified or added. peerings = self.bgp.get('bgp_peering', None) if peerings: for peer in peerings: peering, created = get_or_create_bgp_peering( peer.pop('name')) if created: changed = True # Update the peering on the interface if self.update_bgp_peering( engine, peering, peer): changed = True if self.netlinks: if self.update_netlinks(engine): changed = True if self.tags: if self.add_tags(engine, self.tags): changed = True else: if self.clear_tags(engine): changed = True elif state == 'absent': if engine: engine.delete() self.results['state'].append({ 'name': engine.name, 'type': engine.type, 'action': 'deleted' }) changed = True except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) if not changed and self.results.get('state'): changed = True self.results['changed'] = changed return self.results
def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) changed = False try: # Now that we have valid option settings, we can hit the db if self.policy: policy = FirewallPolicy.get(self.policy) else: policy = FirewallSubPolicy.get(self.sub_policy) if state == 'present': for rule in self.rules: try: validate_rule(rule) except Exception as e: self.fail(msg=str(e)) self.cache = Cache() for rule in self.rules: # Resolve elements if they exist, calls to SMC could happen here if 'sources' in rule: self.field_resolver(rule.get('sources'), rule_targets) if 'destinations' in rule: self.field_resolver(rule.get('destinations'), rule_targets) if 'services' in rule: self.field_resolver(rule.get('services'), service_targets) if 'vpn_policy' in rule: self.cache._add_entry('vpn', rule.get('vpn_policy')) if 'sub_policy' in rule: self.cache._add_entry('sub_ipv4_fw_policy', rule.get('sub_policy')) if 'authentication_options' in rule: auth = rule['authentication_options'] if auth.get('require_auth'): for method in auth.get('methods'): self.cache._add_entry('authentication_service', method) for accounts in ('users', 'groups'): self.cache._add_user_entries( accounts, auth.get(accounts, [])) if self.cache.missing: self.fail( msg= 'Missing required elements that are referenced in this ' 'configuration: %s' % self.cache.missing) if self.check_mode: return self.results for rule in self.rules: rule_dict = {} if 'log_options' in rule: log_options = LogOptions() _log = rule['log_options'] for name, value in log_options.items(): if name not in _log: log_options.pop(name) log_options.update(rule.get('log_options', {})) rule_dict.update(log_options=log_options) if 'connection_tracking' in rule: connection_tracking = ConnectionTracking() _ct = rule['connection_tracking'] for name, value in connection_tracking.items(): if name not in _ct: connection_tracking.pop(name) connection_tracking.update( rule.get('connection_tracking', {})) rule_dict.update( connection_tracking=connection_tracking) action = Action() action.action = rule.get('action', 'allow') if 'inspection_options' in rule: _inspection = rule['inspection_options'] for option in inspection_options: if option in _inspection: action[option] = _inspection.get(option) if 'authentication_options' in rule: _auth_options = rule['authentication_options'] auth_options = AuthenticationOptions() if _auth_options.get('require_auth'): auth_options.update(methods=[ self.get_value('authentication_service', m).href for m in _auth_options.get('methods', []) ], require_auth=True) auth_options.update(users=[ entry.href for entry in self.cache.get_type( 'user_element') ]) rule_dict.update(authentication_options=auth_options) rule_dict.update(action=action) for field in ('sources', 'destinations', 'services'): rule_dict[field] = self.get_values( rule.get(field, None)) rule_dict.update( vpn_policy=self.get_value('vpn', rule.get('vpn_policy')), sub_policy=self.get_value('sub_ipv4_fw_policy', rule.get('sub_policy')), mobile_vpn=rule.get('mobile_vpn', False)) if 'comment' in rule: rule_dict.update(comment=rule.get('comment')) rule_dict.update(name=rule.get('name'), is_disabled=rule.get( 'is_disabled', False)) if 'tag' not in rule: # If no tag is present, this is a create rule_dict.update(before=rule.get('add_before'), after=rule.get('add_after')) rule = policy.fw_ipv4_access_rules.create(**rule_dict) changed = True self.results['state'].append({ 'rule': rule.name, 'type': rule.typeof, 'action': 'created' }) else: # Modify as rule has 'tag' defined. Fetch the rule first # by it's tag reference, skip if tag not found target_rule = self.rule_by_tag(policy, rule.get('tag')) if not target_rule: continue changes = compare_rules(target_rule, rule_dict) # Changes have already been merged if any if rule.get('add_after', None): rule_at_pos = self.rule_by_tag( policy, rule.get('add_after')) if rule_at_pos: target_rule.move_rule_after(rule_at_pos) changes.append('add_after') elif rule.get('add_before', None): rule_at_pos = self.rule_by_tag( policy, rule.get('add_before')) if rule_at_pos: target_rule.move_rule_before(rule_at_pos) changes.append('add_before') elif changes: target_rule.save() if changes: changed = True self.results['state'].append({ 'rule': target_rule.name, 'type': target_rule.typeof, 'action': 'modified', 'changes': changes }) elif state == 'absent': for rule in self.rules: if 'tag' in rule: target_rule = self.rule_by_tag(policy, rule.get('tag')) if target_rule: target_rule.delete() changed = True self.results['state'].append({ 'rule': target_rule.name, 'type': target_rule.typeof, 'action': 'deleted' }) except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) self.results['changed'] = changed return self.results
def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) rbvpn = self.fetch_element(RouteVPN) changed = False if state == 'present': # Short circuit disable if rbvpn and self.enabled is not None and (rbvpn.enabled and not self.enabled): rbvpn.disable() self.results['changed'] = True return self.results local_engine = self.get_managed_gateway(self.local_gw) local_tunnel_interface = self.get_tunnel_interface( local_engine, self.local_gw.get('tunnel_interface')) local_internal_endpoint = self.get_ipsec_endpoint( local_engine, self.local_gw.get('interface_id'), address=self.local_gw.get('address')) if self.remote_gw.get('type', None) != 'external_gateway': remote_engine = self.get_managed_gateway(self.remote_gw) remote_tunnel_interface = self.get_tunnel_interface( remote_engine, self.remote_gw.get('tunnel_interface')) remote_internal_endpoint = self.get_ipsec_endpoint( remote_engine, self.remote_gw.get('interface_id'), address=self.remote_gw.get('address')) else: # External Gateway req = ('name', 'preshared_key', 'external_endpoint') for required in req: if required not in self.remote_gw: self.fail( msg= 'Missing required field for the external endpoint ' 'configuration: %s' % required) external_gateway = dict(name=self.remote_gw['name']) # External Endpoints are defined in the External Gateway. # Build the data structures for a call to ExternalGateway.update_or_create external_endpoint = [] for endpoint in self.remote_gw['external_endpoint']: if 'name' not in endpoint or 'address' not in endpoint: self.fail( msg='An external endpoint must have at least a ' 'name and an address definition.') external_endpoint.append(endpoint) external_gateway.update(external_endpoint=external_endpoint) # Verify specified VPN Sites exist before continuing if 'vpn_site' in self.remote_gw: site_name = self.remote_gw.get('vpn_site', {}).pop('name', None) if not site_name: self.fail(msg='A VPN site requires a name to continue') # Get the elements cache = Cache() cache.add(self.remote_gw.get('vpn_site', {})) if cache.missing: self.fail( msg='Could not find the specified elements for the ' 'VPN site configuration: %s' % cache.missing) site_element = [ value.href for _, values in cache.cache.items() for value in values ] external_gateway.update(vpn_site=[ dict(name=site_name, site_element=site_element) ]) try: if state == 'present': if self.check_mode: return self.results # Create the tunnel endpoints if not rbvpn: local_gateway = TunnelEndpoint.create_ipsec_endpoint( local_engine.vpn.internal_gateway, local_tunnel_interface) # Enable the IPSEC listener on specified interface/s if self.update_ipsec_listener(local_internal_endpoint): changed = True is_external = self.remote_gw.get( 'type', None) == 'external_gateway' if not is_external: remote_gateway = TunnelEndpoint.create_ipsec_endpoint( remote_engine.vpn.internal_gateway, remote_tunnel_interface) if self.update_ipsec_listener( remote_internal_endpoint): changed = True else: # Update or Create gw, updated, created = ExternalGateway.update_or_create( with_status=True, **external_gateway) remote_gateway = TunnelEndpoint.create_ipsec_endpoint( gw) if created or updated: changed = True vpn = dict(name=self.name, local_endpoint=local_gateway, remote_endpoint=remote_gateway) if is_external: vpn.update( preshared_key=self.remote_gw['preshared_key']) rbvpn = RouteVPN.create_ipsec_tunnel(**vpn) changed = True else: #TODO: Update or create from top level RBVPN #rbvpn.update_or_create() if rbvpn and self.enabled is not None and ( not rbvpn.enabled and self.enabled): rbvpn.enable() changed = True if self.remote_gw.get('type') == 'external_gateway': gw, updated, created = ExternalGateway.update_or_create( with_status=True, **external_gateway) if updated or created: changed = True self.results['state'] = rbvpn.data.data self.results['changed'] = changed elif state == 'absent': if rbvpn: rbvpn.delete() changed = True except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) self.results['changed'] = changed return self.results
def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) ELEMENT_TYPES = element_type_dict() try: if state == 'present': deferred_elements = ('group', 'netlink') # Validate elements before proceeding. groups, netlinks = [], [] for element in self.elements: self.is_element_valid(element, ELEMENT_TYPES) if 'group' in element: groups.append(element) elif 'netlink' in element: netlinks.append(element) if groups or netlinks: to_be_created = self.to_be_created_elements() self.cache = Cache() if groups: self.enum_group_members(groups, to_be_created) if self.cache.missing: self.fail( msg= 'Group members referenced are missing and are not being ' 'created in this playbook: %s' % self.cache.missing) if netlinks: self.enum_netlink_members(netlinks, to_be_created) if self.cache.missing: self.fail( msg= 'Netlink elements referenced are missing and are not being ' 'created in this playbook: %s' % self.cache.missing) for element in self.elements: for typeof, _ in element.items(): if typeof not in deferred_elements: result = update_or_create( element, ELEMENT_TYPES, check_mode=self.check_mode) self.results['state'].append(result) for group in groups: # Run through cache again, entries that exist will not be # added twice but this captures elements that might have been # added earlier by the playbook run _group = copy.deepcopy(group) members = _group.get('group', {}).get('members', {}) if members: self.cache.add_many([members]) # Add to new members list _members = [ self.cache.get(typeof, value) for typeof, member in members.items() for value in member ] else: # No members defined _members = [] _group.setdefault('group', {}).update(members=_members) result = update_or_create(_group, ELEMENT_TYPES, check_mode=self.check_mode) self.results['state'].append(result) for netlink in netlinks: _netlink = copy.deepcopy(netlink) gateway = _netlink.get('netlink', {}).get('gateway') self.cache._add_entry(gateway.get('type'), gateway.get('name')) _netlink.setdefault('netlink').update( gateway=self.cache.get(gateway.get('type'), gateway.get('name'))) # Update networks networks = _netlink.get('netlink').get('network') for net in networks: self.cache._add_entry('network', net) _netlink.setdefault('netlink').update(network=[ self.cache.get('network', net) for net in networks ]) result = update_or_create(_netlink, ELEMENT_TYPES, check_mode=self.check_mode) self.results['state'].append(result) if self.check_mode: return self.results else: for element in self.elements: for typeof in element: if typeof not in ELEMENT_TYPES: self.fail( msg= 'Element specified is not valid, got: {}, valid: {}' .format(typeof, ELEMENT_TYPES.keys())) else: if not self.check_mode: for elements in element[typeof]: result = delete_element( ELEMENT_TYPES.get(typeof)['type']( elements), self.ignore_err_if_not_found) self.results['state'].append(result) except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) for results in self.results['state']: if 'action' in results: self.results['changed'] = True break return self.results
def exec_module(self, **kwargs): state = kwargs.pop('state', 'present') for name, value in kwargs.items(): setattr(self, name, value) changed = False if state == 'present': external_gateway = {'name': self.name} # External Endpoints are defined in the External Gateway. # Build the data structures for a call to ExternalGateway.update_or_create external_endpoint = [] for endpoint in self.external_endpoint: if 'name' not in endpoint or 'address' not in endpoint: self.fail(msg='An external endpoint must have at least a ' 'name and an address definition.') external_endpoint.append(endpoint) external_gateway.update(external_endpoint=external_endpoint) if self.vpn_site: site_name = self.vpn_site.pop('name', None) if not site_name: self.fail(msg='VPN site requires a name attribute') cache = Cache() cache.add(self.vpn_site) if cache.missing: self.fail( msg='Could not find the specified elements for the ' 'VPN site configuration: %s' % cache.missing) site_element = [ value.href for _, values in cache.cache.items() for value in values ] external_gateway.update( vpn_site=[dict(name=site_name, site_element=site_element)]) try: if state == 'present': gateway, updated, created = ExternalGateway.update_or_create( with_status=True, **external_gateway) if created or updated: self.results['state'].append({ 'name': gateway.name, 'type': gateway.typeof, 'action': 'created' if created else 'modified' }) changed = True if self.tags: if self.add_tags(gateway, self.tags): changed = True elif state == 'absent': result = delete_element(ExternalGateway(self.name), self.ignore_err_if_not_found) if 'action' in result: changed = True self.results['state'].append(result) except SMCException as err: self.fail(msg=str(err), exception=traceback.format_exc()) self.results['changed'] = changed return self.results