google / capirca

Multi-platform ACL generation system
Apache License 2.0
779 stars 210 forks source link

SRX Address-set and Cisco/Cisco ASA Object-Group Bugs with Optimization/Nested Groups and Multiple Sets of Source/Dest Addresses #121

Open sjtarik opened 7 years ago

sjtarik commented 7 years ago

Multiple instances of the same network object-group will be generated if multiple filters with object groups used.

NETWORK.net file

GROUPA = SUBGROUP1
         SUBGROUP2
         SUBGROUP3

GROUPB = SUBGROUP1
         SUBGROUP4

SUBGROUP1 = 1.1.1.1/32
SUBGROUP2 = 2.2.2.2/32
SUBGROUP3 = 3.3.3.3/32
SUBGROUP4 = 4.4.4.4/32

cisco_sample_policy.pol file

header {
  comment:: "first-group-acl-a"
  target:: cisco first-group-acl-a object-group
}
term permit-all-from-groupa {
  source-address:: GROUPA
  action:: accept
}
term permit-all-from-groupa {
  destination-address:: GROUPB
  action:: accept
}

header {
  comment:: "first-group-acl-b"
  target:: cisco first-group-acl-b object-group
}
term permit-all-from-groupb {
  source-address:: GROUPA
  action:: accept
}

cisco_sample_policy.acl file

object-group network ipv4 GROUPA
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
exit

object-group network ipv4 GROUPA
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
exit

object-group network ipv4 GROUPB
 1.1.1.1/32
 4.4.4.4/32
exit

! $Id:$
! $Date:$
! $Revision:$
no ip access-list extended first-group-acl-a
ip access-list extended first-group-acl-a
 remark $Id:$
 remark first-group-acl-a

 remark permit-all-from-groupa
 permit ip net-group GROUPA any

 remark permit-all-from-groupa
 permit ip any net-group GROUPB

exit

no ip access-list extended first-group-acl-b
ip access-list extended first-group-acl-b
 remark $Id:$
 remark first-group-acl-b

 remark permit-all-from-groupb
 permit ip net-group GROUPA any

exit
sjtarik commented 7 years ago

Multiple instances of same object-group with different ip sets will be created, result in unintended output if multiple subnets passed as source and/or destination.

NETWORK.net file

GROUPA = SUBGROUP1
         SUBGROUP2
         SUBGROUP3

GROUPB = SUBGROUP1
         SUBGROUP4

SUBGROUP1 = 1.1.1.1/32
SUBGROUP2 = 2.2.2.2/32
SUBGROUP3 = 3.3.3.3/32
SUBGROUP4 = 4.4.4.4/32

cisco_sample_policy.pol file

header {
  comment:: "first-group-acl-a"
  target:: cisco first-group-acl-a object-group
}
term permit-all-from-groupa {
  source-address:: GROUPA
  action:: accept
}
term permit-all-from-groupa {
  destination-address:: GROUPB
  action:: accept
}

header {
  comment:: "first-group-acl-b"
  target:: cisco first-group-acl-b object-group
}
term permit-all-from-groupb {
  source-address:: GROUPA GROUPB <========== All addresses will be consolidated under A
  action:: accept
}

cisco_sample_policy.acl file

object-group network ipv4 GROUPA
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
 4.4.4.4/32
exit

object-group network ipv4 GROUPA
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
exit

object-group network ipv4 GROUPB
 1.1.1.1/32
 4.4.4.4/32
exit

! $Id:$
! $Date:$
! $Revision:$
no ip access-list extended first-group-acl-a
ip access-list extended first-group-acl-a
 remark $Id:$
 remark first-group-acl-a

 remark permit-all-from-groupa
 permit ip net-group GROUPA any

 remark permit-all-from-groupa
 permit ip any net-group GROUPB

exit

no ip access-list extended first-group-acl-b
ip access-list extended first-group-acl-b
 remark $Id:$
 remark first-group-acl-b

 remark permit-all-from-groupb
 permit ip net-group GROUPA any

exit
sjtarik commented 7 years ago

Final issue is the hardest one to crack. When optimization is done, group context is lost if any subnet under the main group is optimized/merged. In below example SUBGROUP1 and SUBGROUP2 is merged so that their parent token is SUBGROUP1 and no longer GROUPA or GROUPB. Since cisco generator use the parent token to name object group, both object-group names become SUBGROUP1 when two filters are generated. Due to an earlier reported issue with optimize flag, first term with object-group not optimized and usually rendered correctly but following terms will have issues.

NETWORK.net file

GROUPA = SUBGROUP1
         SUBGROUP2
         SUBGROUP3

GROUPB = SUBGROUP1
         SUBGROUP2
         SUBGROUP4

SUBGROUP1 = 10.16.128.6/32
SUBGROUP2 = 10.16.128.7/32

SUBGROUP3 = 11.11.11.4/32
            17.17.17.17/32
SUBGROUP4 = 14.14.14.14/32
            192.168.1.1/32
            192.168.1.1/32
            192.168.2.12/32
            192.168.3.13/32
            192.168.4.14/32
            192.168.5.15/32
            192.168.6.16/32
            192.168.7.17/32
            192.168.8.18/32
            192.168.9.19/32
            192.168.10.122/32
            192.168.11.133/32
            192.168.12.155/32

cisco_sample_policy.pol file

header {
  comment:: "first-group-acl-b"
  target:: cisco first-group-acl-b object-group
}
term permit-all-from-group0 {
  source-address:: GROUPA
  protocol:: tcp
  action:: deny
}
term permit-all-from-groupa {
  destination-address:: GROUPA
  action:: accept
}
term permit-all-from-groupb {
  destination-address:: GROUPA
  action:: accept
}
term permit-all-from-groupc {
  destination-address:: GROUPB
  action:: accept
}

cisco_sample_policy.acl file

object-group network ipv4 GROUPA
 10.16.128.6/32
 10.16.128.7/32
 11.11.11.4/32
 17.17.17.17/32
exit

object-group network ipv4 SUBGROUP1
 10.16.128.6/31
 11.11.11.4/32
 17.17.17.17/32
exit

! $Id:$
! $Date:$
! $Revision:$
no ip access-list extended first-group-acl-b
ip access-list extended first-group-acl-b
 remark $Id:$
 remark first-group-acl-b

 remark permit-all-from-group0
 deny tcp net-group GROUPA any <===== not optimized since corrent due to optimize flag bug

 remark permit-all-from-groupa
 permit ip any net-group SUBGROUP1 <====== GROUP A is used in pol but rendered SUBGROUP1 

 remark permit-all-from-groupb
 permit ip any net-group SUBGROUP1 <====== GROUP A is used in pol but SUBGROUP1 

 remark permit-all-from-groupc
 permit ip any net-group SUBGROUP1 <====== GROUP B is used in pol but rendered wrong

exit
sjtarik commented 7 years ago

For last comment, the intended output is below. Generated with the fix in pull request.

object-group network ipv4 GROUPA
 10.16.128.6/31
 11.11.11.4/32
 17.17.17.17/32
exit

object-group network ipv4 GROUPB
 10.16.128.6/31
 14.14.14.14/32
 192.168.1.1/32
 192.168.2.12/32
 192.168.3.13/32
 192.168.4.14/32
 192.168.5.15/32
 192.168.6.16/32
 192.168.7.17/32
 192.168.8.18/32
 192.168.9.19/32
 192.168.10.122/32
 192.168.11.133/32
 192.168.12.155/32
exit

! $Id:$
! $Date:$
! $Revision:$
no ip access-list extended first-group-acl-b
ip access-list extended first-group-acl-b
 remark $Id:$
 remark first-group-acl-b

 remark permit-all-from-group0
 deny tcp net-group GROUPA any

 remark permit-all-from-groupa
 permit ip any net-group GROUPA

 remark permit-all-from-groupb
 permit ip any net-group GROUPA

 remark permit-all-from-groupc
 permit ip any net-group GROUPB

exit
sjtarik commented 7 years ago

I am able to recreate a similar scenario when multiple address sets passed to SRX source-address or destination address and the address sets can be summarized. In the below example FOO and BAR is summarized into set FOO_0 and passing multiple sets in term "accept-another" changes the behavior of term "accept-something" allowing a larger set of IPs to pass TCP traffic.

# Network Definition file

FOO = 10.16.128.6/32
BAR = 10.16.128.7/32

# SRX policy file

header {
  comment:: "this is a sample policy to generate Juniper SRX filter"
  comment:: "from zone Untrust to zone DMZ."
  target:: srx from-zone Untrust to-zone DMZ
}

term test-tcp {
  destination-address:: RFC1918
  protocol:: tcp udp
  logging:: true
  action:: accept
}

term test-icmp {
  destination-address:: RFC1918
  protocol:: icmp
  icmp-type:: echo-request echo-reply
  action:: accept
}

term accept-something {
  destination-address:: FOO
  protocol:: tcp
  action:: accept
}

term accept-another {
  destination-address:: FOO
  destination-address:: BAR
  protocol:: udp
  action:: accept
}

term accept-another-last {
  destination-address:: BAR
  protocol:: udp
  action:: deny
}

term default-deny {
  action:: deny
}

# SRX Filter

security {
    replace: address-book {
        global {
                address BAR_0 10.16.128.7/32;
                address FOO_0 10.16.128.6/31;
                address RFC1918_0 10.0.0.0/8;
                address RFC1918_1 172.16.0.0/12;
                address RFC1918_2 192.168.0.0/16;
                address-set BAR {
                    address BAR_0;
                }
                address-set FOO {
                    address FOO_0;
                }
                address-set RFC1918 {
                    address RFC1918_0;
                    address RFC1918_1;
                    address RFC1918_2;
                }
        }
    }
    /*
    $Id:$
    $Date:$
    $Revision:$
    */
    replace: policies {
        /*
        this is a sample policy to generate Juniper SRX filter
        from zone Untrust to zone DMZ.
        */
        from-zone Untrust to-zone DMZ {
            policy test-tcp {
                match {
                    source-address any;
                    destination-address [ RFC1918 ];
                    application test-tcp-app;
                }
                then {
                    permit;
                    log {
                        session-init;
                    }
                }
            }
            policy test-icmp {
                match {
                    source-address any;
                    destination-address [ RFC1918 ];
                    application test-icmp-app;
                }
                then {
                    permit;
                }
            }
            policy accept-something {
                match {
                    source-address any;
                    destination-address [ FOO ];
                    application accept-something-app;
                }
                then {
                    permit;
                }
            }
            policy accept-another {
                match {
                    source-address any;
                    destination-address [ FOO ];
                    application accept-another-app;
                }
                then {
                    permit;
                }
            }
            policy accept-another-last {
                match {
                    source-address any;
                    destination-address [ BAR ];
                    application accept-another-app;
                }
                then {
                    deny;
                }
            }
            policy default-deny {
                match {
                    source-address any;
                    destination-address any;
                    application any;
                }
                then {
                    deny;
                }
            }
        }
    }
}
replace: applications {
    application accept-another-app1 {
        term t1 protocol udp;
    }
    application accept-something-app1 {
        term t1 protocol tcp;
    }
    application test-icmp-app {
        term t1 protocol icmp icmp-type 0 inactivity-timeout 60;
        term t2 protocol icmp icmp-type 8 inactivity-timeout 60;
    }
    application test-tcp-app1 {
        term t1 protocol tcp;
    }
    application test-tcp-app2 {
        term t2 protocol udp;
    }
    application-set accept-another-app {
        application accept-another-app1;
    }
    application-set accept-something-app {
        application accept-something-app1;
    }
    application-set test-tcp-app {
        application test-tcp-app1;
        application test-tcp-app2;
    }
}
sjtarik commented 7 years ago

Anywhere we refer a set of IP addresses by IP address parent_token field, we need to go over and make sure there is no conflict when other terms in the policy also use the same token defined in definition file. Because operations like nacaddr/CollapseAddrListRecursive or junipersrx/_FixLargePolices may change the parent token name or the set of IPs in a group represented by a token.

sjtarik commented 7 years ago

First of the fix is posted in #145 for both srx and ios versions.

earlier broken filters now rendered as follows:

security {
    replace: address-book {
        global {
                address BAR_0 10.16.128.6/31;
                address BAR_v1_0 10.16.128.7/32;
                address FOO_0 10.16.128.6/32;
                address RFC1918_0 10.0.0.0/8;
                address RFC1918_1 172.16.0.0/12;
                address RFC1918_2 192.168.0.0/16;
                address-set BAR {
                    address BAR_0;
                }
                address-set BAR_v1 {
                    address BAR_v1_0;
                }
                address-set FOO {
                    address FOO_0;
                }
                address-set RFC1918 {
                    address RFC1918_0;
                    address RFC1918_1;
                    address RFC1918_2;
                }
        }
    }
    /*
    $Id:$
    $Date:$
    $Revision:$
    */
    replace: policies {
        /*
        this is a sample policy to generate Juniper SRX filter
        from zone Untrust to zone DMZ.
        */
        from-zone Untrust to-zone DMZ {
            policy test-tcp {
                match {
                    source-address any;
                    destination-address [ RFC1918 ];
                    application test-tcp-app;
                }
                then {
                    permit;
                    log {
                        session-init;
                    }
                }
            }
            policy test-icmp {
                match {
                    source-address any;
                    destination-address [ RFC1918 ];
                    application test-icmp-app;
                }
                then {
                    permit;
                }
            }
            policy accept-something {
                match {
                    source-address any;
                    destination-address [ FOO ];
                    application accept-something-app;
                }
                then {
                    permit;
                }
            }
            policy accept-another {
                match {
                    source-address any;
                    destination-address [ BAR ];
                    application accept-another-app;
                }
                then {
                    permit;
                }
            }
            policy accept-another-last {
                match {
                    source-address any;
                    destination-address [ BAR_v1 ];
                    application accept-another-app;
                }
                then {
                    deny;
                }
            }
            policy default-deny {
                match {
                    source-address any;
                    destination-address any;
                    application any;
                }
                then {
                    deny;
                }
            }
        }
    }
}
replace: applications {
    application accept-another-app1 {
        term t1 protocol udp;
    }
    application accept-something-app1 {
        term t1 protocol tcp;
    }
    application test-icmp-app {
        term t1 protocol icmp icmp-type 0 inactivity-timeout 60;
        term t2 protocol icmp icmp-type 8 inactivity-timeout 60;
    }
    application test-tcp-app1 {
        term t1 protocol tcp;
    }
    application test-tcp-app2 {
        term t2 protocol udp;
    }
    application-set accept-another-app {
        application accept-another-app1;
    }
    application-set accept-something-app {
        application accept-something-app1;
    }
    application-set test-tcp-app {
        application test-tcp-app1;
        application test-tcp-app2;
    }
}

and for ios

object-group network ipv4 GROUPA_1
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
 4.4.4.4/32
exit

object-group network ipv4 GROUPA
 1.1.1.1/32
 2.2.2.2/32
 3.3.3.3/32
exit

object-group network ipv4 GROUPB
 1.1.1.1/32
 4.4.4.4/32
exit

! $Id:$
! $Date:$
! $Revision:$
no ip access-list extended first-group-acl-a
ip access-list extended first-group-acl-a
 remark $Id:$
 remark first-group-acl-a

 remark permit-all-from-groupa
 permit ip net-group GROUPA any

 remark permit-all-from-groupb
 permit ip any net-group GROUPB

exit

no ip access-list extended first-group-acl-b
ip access-list extended first-group-acl-b
 remark $Id:$
 remark first-group-acl-b

 remark permit-all-from-groupb
 permit ip net-group GROUPA_1 any

exit