Skip to content

Commit

Permalink
Handle internal IPs in rule block (#297)
Browse files Browse the repository at this point in the history
  • Loading branch information
haim-kermany authored Mar 4, 2025
1 parent 5f0f4d7 commit 30f108e
Show file tree
Hide file tree
Showing 12 changed files with 28,819 additions and 10 deletions.
4 changes: 4 additions & 0 deletions pkg/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ var allTests = []analyzerTest{
name: "ExampleExclude",
exData: data.ExampleExclude,
},
{
name: "Example1dExternalWithSegments",
exData: data.Example1dExternalWithSegments,
},
}

func (a *analyzerTest) file() string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Analyzed connectivity:
Source |Destination |Permitted connections
A |B |TCP dst-ports: 445
B |C-no-address |TCP dst-ports: 443

7 changes: 5 additions & 2 deletions pkg/configuration/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type nsxConfigParser struct {
groupPathsToObjects map[string]*collector.Group
servicePathsToObjects map[string]*collector.Service
topology *nsxTopology
ruleBlockPerEP map[topology.Endpoint][]*topology.RuleIPBlock // map from vm to its blocks
}

func (p *nsxConfigParser) init() {
Expand All @@ -61,6 +62,7 @@ func (p *nsxConfigParser) init() {
p.servicePathsToObjects = map[string]*collector.Service{}
p.groupToVMsListCache = map[*collector.Group][]topology.Endpoint{}
p.servicePathToConnCache = map[string]*netset.TransportSet{}
p.ruleBlockPerEP = map[topology.Endpoint][]*topology.RuleIPBlock{}
}

func (p *nsxConfigParser) runParser() error {
Expand Down Expand Up @@ -119,7 +121,7 @@ func (p *nsxConfigParser) storeParsedSegments() {
func (p *nsxConfigParser) removeVMsWithoutGroups() {
toRemove := []topology.Endpoint{}
for vm, groups := range p.configRes.GroupsPerVM {
if len(groups) == 0 {
if len(groups) == 0 && len(p.ruleBlockPerEP[vm]) == 0 {
logging.Debugf("ignoring VM without groups: %s", vm.Name())
toRemove = append(toRemove, vm)
}
Expand Down Expand Up @@ -308,7 +310,8 @@ func (p *nsxConfigParser) getAllGroups() {

func (p *nsxConfigParser) getEndpointsFromScopePaths(groupsPaths []string) ([]topology.Endpoint, []*collector.Group) {
if slices.Contains(groupsPaths, anyStr) {
return append(p.allGroupsVMs, p.configRes.externalIPs...), p.allGroups // all endpoints and groups
// in scope - "any" are all the vms and external endpoints
return p.configRes.Endpoints(), p.allGroups // all endpoints and groups
}
endPoints, groups, _ := p.getEndpointsFromGroupsPaths(groupsPaths, false)
return endPoints, groups
Expand Down
38 changes: 35 additions & 3 deletions pkg/configuration/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (p *nsxConfigParser) getTopology() (err error) {
}
p.getAllRulesIPBlocks()
p.getExternalIPs()
// todo - calc VMs of the block
p.getRuleBlocksVMs()
return nil
}

Expand Down Expand Up @@ -81,8 +81,7 @@ func (p *nsxConfigParser) getAllRulesIPBlocks() {
}
}
// remove duplications, "ANY" and paths to groups:
slices.Sort(allIPs)
allIPs = slices.Compact(allIPs)
allIPs = common.SliceCompact(allIPs)
allIPs = slices.DeleteFunc(allIPs, func(path string) bool { return path == anyStr || slices.Contains(p.allGroupsPaths, path) })
// create the blocks:
for _, ip := range allIPs {
Expand Down Expand Up @@ -117,7 +116,40 @@ func (p *nsxConfigParser) getExternalIPs() {
for _, externalIP := range p.configRes.externalIPs {
if externalIP.(*topology.ExternalIP).Block.IsSubset(ruleBlock.Block) {
ruleBlock.ExternalIPs = append(ruleBlock.ExternalIPs, externalIP)
p.ruleBlockPerEP[externalIP] = append(p.ruleBlockPerEP[externalIP], ruleBlock)
}
}
}
}

func (p *nsxConfigParser) getRuleBlocksVMs() {
for _, block := range p.topology.allRuleIPBlocks {
// iterate over VMs, look if the vm address is in the block:
for _, vm := range p.configRes.VMs {
for _, address := range vm.(*topology.VM).IPAddresses() {
address, err := netset.IPBlockFromIPAddress(address)
if err != nil {
logging.Warnf("Could not resolve address %s of vm %s", address, vm.Name())
continue
}
if address.IsSubset(block.Block) {
block.VMs = append(block.VMs, vm)
p.ruleBlockPerEP[vm] = append(p.ruleBlockPerEP[vm], block)
}
}
}
// iterate over segments, if segment is in the block, add all its vms
for _, segment := range p.topology.segments {
if segment.Block.IsSubset(block.Block) {
block.VMs = append(block.VMs, segment.VMs...)
for _, vm := range segment.VMs {
p.ruleBlockPerEP[vm] = append(p.ruleBlockPerEP[vm], block)
}
}
}
block.VMs = common.SliceCompact(block.VMs)
}
for _, vm := range p.configRes.VMs {
p.ruleBlockPerEP[vm] = common.SliceCompact(p.ruleBlockPerEP[vm])
}
}
41 changes: 41 additions & 0 deletions pkg/data/examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,47 @@ var Example1d = Example{
},
},
}
var Example1dExternalWithSegments = Example{
Name: "Example1dExternalWithSegments",
VMs: []string{"A", "B", "C-no-address"},
VMsAddress: map[string]string{
"A": "0.0.1.0",
"B": "0.0.1.192",
},
SegmentsByVMs: map[string][]string{
"seg_a_and_b": {"A", "B"},
"seg_c": {"C-no-address"},
},
SegmentsBlock: map[string]string{
"seg_a_and_b": "0.0.1.0/24",
"seg_c": "0.0.2.0/24",
},
Policies: []Category{
{
Name: "app-x",
CategoryType: "Application",
Rules: []Rule{
{
Name: "allow_smb_a_to_b",
ID: 1004,
Source: "0.0.1.0/25",
Dest: "0.0.1.128/25",
Services: []string{"/infra/services/SMB"},
Action: Allow,
},
{
Name: "allow_https_b_to_c",
ID: 1005,
Source: "0.0.1.128/25",
Dest: "0.0.2.0/24",
Services: []string{"/infra/services/HTTPS"},
Action: Allow,
},
DefaultDenyRule(denyRuleIDApp),
},
},
},
}

var Example1External = Example{
Name: "Example1External",
Expand Down
47 changes: 42 additions & 5 deletions pkg/data/examples_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import (
// Example is in s single domain
type Example struct {
// nsx config spec fields below
VMs []string
VMsTags map[string][]nsx.Tag
GroupsByVMs map[string][]string
GroupsByExpr map[string]ExampleExpr // map from group name to its expr
Policies []Category
VMs []string
VMsTags map[string][]nsx.Tag
VMsAddress map[string]string
GroupsByVMs map[string][]string
SegmentsByVMs map[string][]string
SegmentsBlock map[string]string
GroupsByExpr map[string]ExampleExpr // map from group name to its expr
Policies []Category

// additional info about example, relevant for synthesis
DisjointGroupsTags [][]string
Expand Down Expand Up @@ -49,6 +52,40 @@ func ExamplesGeneration(e *Example, overrideJSON bool) (*collector.ResourcesCont
}
res.VirtualMachineList = append(res.VirtualMachineList, newVMRes)
}
for segmentName, ip := range e.SegmentsBlock {
segment := collector.Segment{
Segment: nsx.Segment{
UniqueId: &segmentName,
DisplayName: &segmentName,
Subnets: []nsx.SegmentSubnet{{Network: &ip}},
Path: &segmentName,
},
}
for _, vm := range e.SegmentsByVMs[segmentName] {
portName := "port_" + vm
port := collector.SegmentPort{
SegmentPort: nsx.SegmentPort{
DisplayName: &portName,
UniqueId: &portName,
ParentPath: &segmentName,
Attachment: &nsx.PortAttachment{
Id: &portName,
},
},
}
vmAddress := nsx.IPAddress(e.VMsAddress[vm])
vni := collector.VirtualNetworkInterface{
VirtualNetworkInterface: nsx.VirtualNetworkInterface{
LportAttachmentId: &portName,
OwnerVmId: &vm,
IpAddressInfo: []nsx.IpAddressInfo{{IpAddresses: []nsx.IPAddress{vmAddress}}},
},
}
res.VirtualNetworkInterfaceList = append(res.VirtualNetworkInterfaceList, vni)
segment.SegmentPorts = append(segment.SegmentPorts, port)
}
res.SegmentList = append(res.SegmentList, segment)
}
// set default domain
domainRsc := collector.Domain{}
defaultName := "default"
Expand Down
Loading

0 comments on commit 30f108e

Please sign in to comment.