防火牆ACL配置自動化 - 配置解析


配置解析,是將不同品牌防火牆,將關鍵信息提取出來,解析到統一的表格中。

這樣,即可開展后續的ACL策略分析,以及自動生成配置。

 

同時,這些表格數據,還可以用於其他途徑,例如:

1)返回NAT信息,不用再逐一登錄防火牆查詢NAT信息

2)服務器下線時,提取所有關聯ACL,NAT配置

3)網絡運維,經常會遇到被要求查詢某個地址/某個網段開過的所有策略,涉及到異構防火牆,靠人工幾乎無法實現,有了統一的防火牆表格數據,就可以輕松實現

 

1,防火牆解析表格設計

分為四個表格:

address:地址表,記錄每個地址組,以及其成員地址

port:端口表,記錄每個端口組,以及其成員

nat:NAT表,記錄防火牆映射關系

acl:策略表,記錄防火牆每條acl信息,需要從address表/port表獲取其成員

表格采用json格式存儲

 

每張表的column字段設計如下:

address:  ['FwName', 'FwIP', 'ID', 'Zone', 'Type', 'Name', 'Members', 'Conf']

port:  ['FwName', 'FwIP', 'ID', 'Type', 'Name', 'Protocol', 'Members1', 'Members2', 'Conf']

nat:  ['FwName', 'FwIP', 'ID', 'Type', 'SrcZone', 'DstZone', 'SrcName', 'SrcMembers', 'SrcTransName', 'SrcTransMembers', 'DstName', 'DstMembers', 'DstTransName', 'DstTransMembers', 'Conf']

acl:   ['FwName', 'FwIP', 'ID', 'PolicyName', 'Action', 'Protocol', 'SrcArea', 'DstArea', 'SrcName', 'SrcMembers', 'DstName', 'DstMembers', 'PortName', 'PortMembers1', 'PortMembers2', 'Conf']

 

2,防火牆解析 - 基類

每個品牌防火牆一個類,繼承自基類,目標是從不同品牌防火牆中提取基類中公共字段(四張表)。

有些內容不支持解析,對以后的防火牆配置自動化可能產生的后果:1)漏開通策略(有deny acl未被解析) 2)多開通策略(已有permit acl未被解析)

但是,如果后續都是按照自動化腳本去生成配置,那就不會存在沒法解析的內容

 

不支持解析的內容有:

1)思科

address(object-network):成員是range的,沒有成員的

address(object-group network):沒有成員的

待補充

 

防火牆基類:

 

class BaseFw:

    ADDRESS_COLUMNS = ['FwName', 'FwIP', 'ID', 'Zone', 'Type', 'Name', 'Members', 'Conf']

    PORT_COLUMNS = ['FwName', 'FwIP', 'ID', 'Type', 'Name', 'Protocol', 'Members1', 'Members2', 'Conf']

    NAT_COLUMNS = ['FwName', 'FwIP', 'ID', 'Type', 'SrcZone', 'DstZone', 'SrcName', 'SrcMembers', 'SrcTransName',
                   'SrcTransMembers', 'DstName', 'DstMembers', 'DstTransName', 'DstTransMembers', 'Conf']

    ACL_COLUMNS = ['FwName', 'FwIP', 'ID', 'PolicyName', 'Action', 'Protocol', 'SrcArea', 'DstArea', 'SrcName',
                   'SrcMembers', 'DstName', 'DstMembers', 'PortName', 'PortMembers1', 'PortMembers2', 'Conf']

    def __init__(self, fw_name, fw_ip, buff, port_pres):
        self.fw_name = fw_name           # 防火牆名稱
        self.fw_ip = fw_ip               # 防火牆IP
        self.buff = buff                 # 防火牆配置
        self.port_pres = []              # 防火牆的端口預配置,是個字典列表,可以從json轉換而來
        for port in port_pres:
            self.port_pres.append({
                "FwName": self.fw_name,
                "FwIP": self.fw_ip,
                "ID": "",
                "Type": "",
                "Name": port.get("name"),
                "Protocol": port.get("protocol"),
                "Members1": str(port.get("port")),  # int -> string
                "members2": str(port.get("port")),
                "Conf": port.get("conf")
            })

思科端口預配置(截取部分)

[
    {
        "name": "aol",
        "protocol": "tcp",
        "port": 5190,
        "conf": "思科預配置端口:aol"
    },
    {
        "name": "bgp",
        "protocol": "tcp",
        "port": 179,
        "conf": "思科預配置端口:bgp"
    },
    {
        "name": "biff",
        "protocol": "tcp",
        "port": 512,
        "conf": "思科預配置端口:biff"
    },
    {
        "name": "bootpc",
        "protocol": "tcp",
        "port": 68,
        "conf": "思科預配置端口:bootpc"
    },
    {
        "name": "bootps",
        "protocol": "tcp",
        "port": 67,
        "conf": "思科預配置端口:bootps"
    }
]

 

 

3,防火牆解析 - 地址組解析

以思科地址組為例,解析所有地址組成員

class FwCisco(BaseFw):

    def __init__(self, fw_name, fw_ip, buff, port_pres):
        super().__init__(fw_name, fw_ip, buff, port_pres)
        self.port_pres_map = {port_pre.get("name"): port_pre.get("port") for port_pre in self.port_pres}

    @LazyProperty
    def address(self):
        items = []

        # object network
        configs = re.findall(r'^(object network (.*?)\n (?:host|subnet) (.*?)\n)', self.buff, re.M)
        # configs = re.findall(r'^(object network (.*?)\n (?:host|subnet|range) (.*?))$', self.buff, re.M)  # 支持range
        for conf, name, member in configs:
            item = [self.fw_name, self.fw_ip, '', '', 'object', name.strip(), member.strip(), conf.strip()]
            items.append({column: value for column, value in zip(self.ADDRESS_COLUMNS, item)})

        # object-group network
        configs = re.finditer(r'^object-group network .*?\n(?=\S)', self.buff, re.M | re.S)
        for conf in configs:
            conf = conf.group()
            members = re.findall(r'network-object (?:host )?(.*?)\n', conf)
            group_objs = re.findall(r'group-object (.*?)\s*$', conf, re.M)
            if group_objs:  # 如果有地址組嵌套地址組, 從被嵌套的地址組中獲取成員
                for group_obj in [i for i in items if i.get("Name") in group_objs]:
                    members += [i for i in group_obj.get("Members").split(",") if i not in members]
            members = ','.join(members)
            if not members:
                continue
            name = re.search(r'object-group network (.*?)\n', conf).group(1)
            item = [self.fw_name, self.fw_ip, '', '', 'object-group', name.strip(), members.strip(), conf.strip()]
            items.append({column: value for column, value in zip(self.ADDRESS_COLUMNS, item)})
        return items

  

 

未完待續

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM