# Copyright 2013 vArmour Networks Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # @author: Gary Duan, gduan@varmour.com, vArmour Networks from neutron.openstack.common import log as logging from neutron.services.firewall.agents.varmour import varmour_api from neutron.services.firewall.agents.varmour import varmour_utils as va_utils from neutron.services.firewall.drivers import fwaas_base LOG = logging.getLogger(__name__) class vArmourFwaasDriver(fwaas_base.FwaasDriverBase): def __init__(self): LOG.debug(_("Initializing fwaas vArmour driver")) self.rest = varmour_api.vArmourRestAPI() def create_firewall(self, apply_list, firewall): LOG.debug(_('create_firewall (%s)'), firewall['id']) return self.update_firewall(apply_list, firewall) def update_firewall(self, apply_list, firewall): LOG.debug(_("update_firewall (%s)"), firewall['id']) if firewall['admin_state_up']: return self._update_firewall(apply_list, firewall) else: return self.apply_default_policy(apply_list, firewall) def delete_firewall(self, apply_list, firewall): LOG.debug(_("delete_firewall (%s)"), firewall['id']) return self.apply_default_policy(apply_list, firewall) def apply_default_policy(self, apply_list, firewall): LOG.debug(_("apply_default_policy (%s)"), firewall['id']) self.rest.auth() for ri in apply_list: self._clear_policy(ri, firewall) return True def _update_firewall(self, apply_list, firewall): LOG.debug(_("Updating firewall (%s)"), firewall['id']) self.rest.auth() for ri in apply_list: self._clear_policy(ri, firewall) self._setup_policy(ri, firewall) return True def _setup_policy(self, ri, fw): # create zones no matter if they exist. Interfaces are added by router body = { 'type': 'L3', 'interface': [] } body['name'] = va_utils.get_trusted_zone_name(ri) self.rest.rest_api('POST', va_utils.REST_URL_CONF_ZONE, body) body['name'] = va_utils.get_untrusted_zone_name(ri) self.rest.rest_api('POST', va_utils.REST_URL_CONF_ZONE, body) self.rest.commit() servs = dict() addrs = dict() for rule in fw['firewall_rule_list']: if not rule['enabled']: continue if rule['ip_version'] == 4: service = self._make_service(ri, fw, rule, servs) s_addr = self._make_address(ri, fw, rule, addrs, True) d_addr = self._make_address(ri, fw, rule, addrs, False) policy = va_utils.get_firewall_policy_name(ri, fw, rule) z0 = va_utils.get_trusted_zone_name(ri) z1 = va_utils.get_untrusted_zone_name(ri) body = self._make_policy(policy + '_0', rule, z0, z0, s_addr, d_addr, service) self.rest.rest_api('POST', va_utils.REST_URL_CONF_POLICY, body) body = self._make_policy(policy + '_1', rule, z0, z1, s_addr, d_addr, service) self.rest.rest_api('POST', va_utils.REST_URL_CONF_POLICY, body) body = self._make_policy(policy + '_2', rule, z1, z0, s_addr, d_addr, service) self.rest.rest_api('POST', va_utils.REST_URL_CONF_POLICY, body) self.rest.commit() else: LOG.warn(_("Unsupported IP version rule.")) def _clear_policy(self, ri, fw): prefix = va_utils.get_firewall_object_prefix(ri, fw) self.rest.del_cfg_objs(va_utils.REST_URL_CONF_POLICY, prefix) self.rest.del_cfg_objs(va_utils.REST_URL_CONF_ADDR, prefix) self.rest.del_cfg_objs(va_utils.REST_URL_CONF_SERVICE, prefix) def _make_service(self, ri, fw, rule, servs): prefix = va_utils.get_firewall_object_prefix(ri, fw) if rule.get('protocol'): key = rule.get('protocol') if rule.get('source_port'): key += '-' + rule.get('source_port') if rule.get('destination_port'): key += '-' + rule.get('destination_port') else: return if key in servs: name = '%s_%d' % (prefix, servs[key]) else: # create new service object with index idx = len(servs) servs[key] = idx name = '%s_%d' % (prefix, idx) body = {'name': name} self.rest.rest_api('POST', va_utils.REST_URL_CONF_SERVICE, body) body = self._make_service_rule(rule) self.rest.rest_api('POST', va_utils.REST_URL_CONF + va_utils.REST_SERVICE_NAME % name, body) self.rest.commit() return name def _make_service_rule(self, rule): body = { 'name': '1', 'protocol': rule.get('protocol') } if 'source_port' in rule: body['source-start'] = rule['source_port'] body['source-end'] = rule['source_port'] if 'destination_port' in rule: body['dest-start'] = rule['destination_port'] body['dest-end'] = rule['destination_port'] return body def _make_address(self, ri, fw, rule, addrs, is_src): prefix = va_utils.get_firewall_object_prefix(ri, fw) if is_src: key = rule.get('source_ip_address') else: key = rule.get('destination_ip_address') if not key: return if key in addrs: name = '%s_%d' % (prefix, addrs[key]) else: # create new address object with idx idx = len(addrs) addrs[key] = idx name = '%s_%d' % (prefix, idx) body = { 'name': name, 'type': 'ipv4', 'ipv4': key } self.rest.rest_api('POST', va_utils.REST_URL_CONF_ADDR, body) self.rest.commit() return name def _make_policy(self, name, rule, zone0, zone1, s_addr, d_addr, service): body = { 'name': name, 'action': 'permit' if rule.get('action') == 'allow' else 'deny', 'from': zone0, 'to': zone1, 'match-source-address': [s_addr or 'Any'], 'match-dest-address': [d_addr or 'Any'], 'match-service': [service or 'Any'] } return body