Skip to content

Commit

Permalink
Support ANP with ICMP Rule (#315)
Browse files Browse the repository at this point in the history
With this PR, Nephe will support icmp protocol in Antrea NetworkPolicy.
Its enabled for both AWS and Azure Cloud. Both ICMP-ALL and ICMP-Custom
are supported. With ICMP-Custom, user can specify ICMP-Type and ICMP-Code
for more granular control.

Signed-off-by: Rahul Jain <[email protected]>
  • Loading branch information
reachjainrahul authored Oct 13, 2023
1 parent 28b1412 commit df221b8
Show file tree
Hide file tree
Showing 14 changed files with 485 additions and 209 deletions.
14 changes: 12 additions & 2 deletions pkg/cloudprovider/cloudresource/cloudresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ var (
CloudSecurityGroupVisibility bool
)

var (
IcmpProtocol = 1
TcpProtocol = 6
UdpProtocol = 17
)

// CloudResourceType specifies the type of cloud resource.
type CloudResourceType string

Expand Down Expand Up @@ -122,28 +128,32 @@ type Rule interface {

// IngressRule specifies one ingress rule of cloud SecurityGroup.
type IngressRule struct {
FromPort *int
FromPort *int32
FromSrcIP []*net.IPNet
FromSecurityGroups []*CloudResourceID
Protocol *int
AppliedToGroup map[string]struct{}
Priority *float64
Action *antreacrdv1beta1.RuleAction
RuleName string
IcmpType *int32
IcmpCode *int32
}

func (i *IngressRule) isRule() {}

// EgressRule specifies one egress rule of cloud SecurityGroup.
type EgressRule struct {
ToPort *int
ToPort *int32
ToDstIP []*net.IPNet
ToSecurityGroups []*CloudResourceID
Protocol *int
AppliedToGroup map[string]struct{}
Priority *float64
Action *antreacrdv1beta1.RuleAction
RuleName string
IcmpType *int32
IcmpCode *int32
}

func (e *EgressRule) isRule() {}
Expand Down
140 changes: 98 additions & 42 deletions pkg/cloudprovider/plugins/aws/aws_converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,28 @@ func convertToIPPermissionProtocol(protocol *int) *string {
return aws.String(strconv.FormatInt(int64(*protocol), 10))
}

func convertToIPPermissionPort(port *int, protocol *int) (*int64, *int64) {
func convertToIPPermissionPort(port *int32, protocol *int, icmpType, icmpCode *int32) (*int64, *int64) {
if port == nil {
// For TCP and UDP, aws expects explicit start and end port numbers (for all ports case)
if protocol != nil && (*protocol == 6 || *protocol == 17) {
return aws.Int64(int64(tcpUDPPortStart)), aws.Int64(int64(tcpUDPPortEnd))
if protocol != nil &&
(*protocol == cloudresource.TcpProtocol || *protocol == cloudresource.UdpProtocol || *protocol == cloudresource.IcmpProtocol) {
if *protocol == cloudresource.IcmpProtocol {
awsIcmpType := aws.Int64(-1)
awsIcmpCode := aws.Int64(-1)
if icmpType != nil {
awsIcmpType = aws.Int64(int64(*icmpType))
}
if icmpCode != nil {
awsIcmpCode = aws.Int64(int64(*icmpCode))
}
return awsIcmpType, awsIcmpCode
} else {
return aws.Int64(int64(tcpUDPPortStart)), aws.Int64(int64(tcpUDPPortEnd))
}
}
return nil, nil
}

portVal := aws.Int64(int64(*port))
return portVal, portVal
}
Expand Down Expand Up @@ -153,7 +167,7 @@ func convertIngressToIpPermission(rules []*cloudresource.CloudRule, cloudSGNameT
}
idGroupPairs := buildEc2UserIDGroupPairs(rule.FromSecurityGroups, cloudSGNameToObj, &description)
ipv4Ranges, ipv6Ranges := convertToEc2IpRanges(rule.FromSrcIP, len(rule.FromSecurityGroups) > 0, &description)
startPort, endPort := convertToIPPermissionPort(rule.FromPort, rule.Protocol)
startPort, endPort := convertToIPPermissionPort(rule.FromPort, rule.Protocol, rule.IcmpType, rule.IcmpCode)
ipPermission := &ec2.IpPermission{
FromPort: startPort,
ToPort: endPort,
Expand Down Expand Up @@ -183,7 +197,7 @@ func convertEgressToIpPermission(rules []*cloudresource.CloudRule, cloudSGNameTo

idGroupPairs := buildEc2UserIDGroupPairs(rule.ToSecurityGroups, cloudSGNameToObj, &description)
ipv4Ranges, ipv6Ranges := convertToEc2IpRanges(rule.ToDstIP, len(rule.ToSecurityGroups) > 0, &description)
startPort, endPort := convertToIPPermissionPort(rule.ToPort, rule.Protocol)
startPort, endPort := convertToIPPermissionPort(rule.ToPort, rule.Protocol, rule.IcmpType, rule.IcmpCode)
ipPermission := &ec2.IpPermission{
FromPort: startPort,
ToPort: endPort,
Expand All @@ -203,18 +217,25 @@ func convertFromIngressIpPermissionToCloudRule(sgID string, ipPermissions []*ec2
managedSGs, unmanagedSGs map[string]*ec2.SecurityGroup) []cloudresource.CloudRule {
var ingressRules []cloudresource.CloudRule
for _, ipPermission := range ipPermissions {
protocol := convertFromIPPermissionProtocol(*ipPermission.IpProtocol)
fromPort, toPort := convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort)
fromSrcIPs, descriptions := convertFromIPRange(ipPermission.IpRanges, ipPermission.Ipv6Ranges)
for i, srcIP := range fromSrcIPs {
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
rule := &cloudresource.IngressRule{
FromSrcIP: []*net.IPNet{srcIP},
Protocol: protocol,
}
if protocol != nil && *protocol == cloudresource.IcmpProtocol {
rule.IcmpType = fromPort
rule.IcmpCode = toPort
} else {
rule.FromPort = fromPort
}
ingressRule := cloudresource.CloudRule{
Rule: &cloudresource.IngressRule{
FromPort: convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort),
FromSrcIP: []*net.IPNet{srcIP},
Protocol: convertFromIPPermissionProtocol(*ipPermission.IpProtocol),
},
Rule: rule,
AppliedToGrp: sgID,
}
desc, ok := utils.ExtractCloudDescription(descriptions[i])
if ok {
ingressRule.NpNamespacedName = types.NamespacedName{Name: desc.Name, Namespace: desc.Namespace}.String()
}
Expand All @@ -223,16 +244,22 @@ func convertFromIngressIpPermissionToCloudRule(sgID string, ipPermissions []*ec2
}
fromSecurityGroups, descriptions := convertFromSecurityGroupPair(ipPermission.UserIdGroupPairs, managedSGs, unmanagedSGs)
for i, SecurityGroup := range fromSecurityGroups {
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
rule := &cloudresource.IngressRule{
FromSecurityGroups: []*cloudresource.CloudResourceID{SecurityGroup},
Protocol: protocol,
}
if protocol != nil && *protocol == cloudresource.IcmpProtocol {
rule.IcmpType = fromPort
rule.IcmpCode = toPort
} else {
rule.FromPort = fromPort
}
ingressRule := cloudresource.CloudRule{
Rule: &cloudresource.IngressRule{
FromPort: convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort),
FromSecurityGroups: []*cloudresource.CloudResourceID{SecurityGroup},
Protocol: convertFromIPPermissionProtocol(*ipPermission.IpProtocol),
},
Rule: rule,
AppliedToGrp: sgID,
}
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
if ok {
ingressRule.NpNamespacedName = types.NamespacedName{Name: desc.Name, Namespace: desc.Namespace}.String()
}
Expand All @@ -249,18 +276,26 @@ func convertFromEgressIpPermissionToCloudRule(sgID string, ipPermissions []*ec2.
managedSGs, unmanagedSGs map[string]*ec2.SecurityGroup) []cloudresource.CloudRule {
var egressRules []cloudresource.CloudRule
for _, ipPermission := range ipPermissions {
protocol := convertFromIPPermissionProtocol(*ipPermission.IpProtocol)
fromPort, toPort := convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort)
toDstIPs, descriptions := convertFromIPRange(ipPermission.IpRanges, ipPermission.Ipv6Ranges)
for i, dstIP := range toDstIPs {
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
rule := &cloudresource.EgressRule{
ToDstIP: []*net.IPNet{dstIP},
Protocol: protocol,
}
if protocol != nil && *protocol == cloudresource.IcmpProtocol {
rule.IcmpType = fromPort
rule.IcmpCode = toPort
} else {
rule.ToPort = fromPort
}
egressRule := cloudresource.CloudRule{
Rule: &cloudresource.EgressRule{
ToPort: convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort),
ToDstIP: []*net.IPNet{dstIP},
Protocol: convertFromIPPermissionProtocol(*ipPermission.IpProtocol),
},
Rule: rule,
AppliedToGrp: sgID,
}
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
if ok {
egressRule.NpNamespacedName = types.NamespacedName{Name: desc.Name, Namespace: desc.Namespace}.String()
}
Expand All @@ -269,16 +304,22 @@ func convertFromEgressIpPermissionToCloudRule(sgID string, ipPermissions []*ec2.
}
toSecurityGroups, descriptions := convertFromSecurityGroupPair(ipPermission.UserIdGroupPairs, managedSGs, unmanagedSGs)
for i, SecurityGroup := range toSecurityGroups {
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
rule := &cloudresource.EgressRule{
ToSecurityGroups: []*cloudresource.CloudResourceID{SecurityGroup},
Protocol: protocol,
}
if protocol != nil && *protocol == cloudresource.IcmpProtocol {
rule.IcmpType = fromPort
rule.IcmpCode = toPort
} else {
rule.ToPort = fromPort
}
egressRule := cloudresource.CloudRule{
Rule: &cloudresource.EgressRule{
ToPort: convertFromIPPermissionPort(ipPermission.FromPort, ipPermission.ToPort),
ToSecurityGroups: []*cloudresource.CloudResourceID{SecurityGroup},
Protocol: convertFromIPPermissionProtocol(*ipPermission.IpProtocol),
},
Rule: rule,
AppliedToGrp: sgID,
}
// Get cloud rule description.
desc, ok := utils.ExtractCloudDescription(descriptions[i])
if ok {
egressRule.NpNamespacedName = types.NamespacedName{Name: desc.Name, Namespace: desc.Namespace}.String()
}
Expand All @@ -289,23 +330,38 @@ func convertFromEgressIpPermissionToCloudRule(sgID string, ipPermissions []*ec2.
return egressRules
}

func convertFromIPPermissionPort(startPort *int64, endPort *int64) *int {
func convertFromIPPermissionPort(startPort *int64, endPort *int64) (*int32, *int32) {
if startPort == nil {
return nil
if endPort == nil {
return nil, nil
} else {
retval := int32(*endPort)
return nil, &retval
}
}
if endPort == nil {
retVal := int(*startPort)
return &retVal
retVal := int32(*startPort)
return &retVal, nil
}
if *startPort == -1 {
return nil
if *endPort == -1 {
return nil, nil
} else {
retval := int32(*endPort)
return nil, &retval
}
}

if *startPort == *endPort {
retVal := int(*startPort)
return &retVal
retVal := int32(*startPort)
return &retVal, nil
} else if *startPort == 0 && *endPort == 65535 {
// (0 - 65535) tcp/udp ports returns nil
return nil, nil
}
// other cases along with all (0 - 65535) tcp/udp ports returns nil
return nil
retval1 := int32(*startPort)
retval2 := int32(*endPort)
return &retval1, &retval2
}

// convertFromIPPermissionPortToString helper function to convert cloud port number field to string.
Expand Down
24 changes: 12 additions & 12 deletions pkg/cloudprovider/plugins/aws/aws_security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ var _ = Describe("AWS Cloud Security", func() {
}
addRule := []*cloudresource.CloudRule{{
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSrcIP: []*net.IPNet{{
IP: net.ParseIP("2600:1f16:c77:a001:fb97:21b2:a8dc:dc60"),
Mask: net.CIDRMask(128, 128)},
Expand Down Expand Up @@ -319,7 +319,7 @@ var _ = Describe("AWS Cloud Security", func() {
}
addRule := []*cloudresource.CloudRule{{
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSrcIP: []*net.IPNet{},
FromSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier.CloudResourceID},
Protocol: aws.Int(6),
Expand Down Expand Up @@ -355,7 +355,7 @@ var _ = Describe("AWS Cloud Security", func() {
}
addRule := []*cloudresource.CloudRule{{
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToDstIP: []*net.IPNet{},
ToSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier.CloudResourceID},
Protocol: aws.Int(6),
Expand Down Expand Up @@ -396,7 +396,7 @@ var _ = Describe("AWS Cloud Security", func() {
}
addRule := []*cloudresource.CloudRule{{
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToDstIP: []*net.IPNet{},
ToSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier.CloudResourceID},
Protocol: aws.Int(6),
Expand Down Expand Up @@ -441,7 +441,7 @@ var _ = Describe("AWS Cloud Security", func() {
addRule := []*cloudresource.CloudRule{
{
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSrcIP: []*net.IPNet{{
IP: net.ParseIP("2600:1f16:c77:a001:fb97:21b2:a8dc:dc60"),
Mask: net.CIDRMask(128, 128)},
Expand All @@ -450,7 +450,7 @@ var _ = Describe("AWS Cloud Security", func() {
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSrcIP: []*net.IPNet{{
IP: net.ParseIP("2600:1f16:c77:a001:fb97:21b2:a8dc:dc61"),
Mask: net.CIDRMask(128, 128)},
Expand All @@ -459,13 +459,13 @@ var _ = Describe("AWS Cloud Security", func() {
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier1.CloudResourceID},
Protocol: aws.Int(6),
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.IngressRule{
FromPort: aws.Int(22),
FromPort: aws.Int32(22),
FromSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier2.CloudResourceID},
Protocol: aws.Int(6),
}, NpNamespacedName: testAnpNamespacedName.String(),
Expand Down Expand Up @@ -543,7 +543,7 @@ var _ = Describe("AWS Cloud Security", func() {
addRule := []*cloudresource.CloudRule{
{
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToDstIP: []*net.IPNet{{
IP: net.ParseIP("2600:1f16:c77:a001:fb97:21b2:a8dc:dc60"),
Mask: net.CIDRMask(128, 128)},
Expand All @@ -552,7 +552,7 @@ var _ = Describe("AWS Cloud Security", func() {
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToDstIP: []*net.IPNet{{
IP: net.ParseIP("2600:1f16:c77:a001:fb97:21b2:a8dc:dc61"),
Mask: net.CIDRMask(128, 128)},
Expand All @@ -561,13 +561,13 @@ var _ = Describe("AWS Cloud Security", func() {
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier1.CloudResourceID},
Protocol: aws.Int(6),
}, NpNamespacedName: testAnpNamespacedName.String(),
}, {
Rule: &cloudresource.EgressRule{
ToPort: aws.Int(22),
ToPort: aws.Int32(22),
ToSecurityGroups: []*cloudresource.CloudResourceID{&webSgIdentifier2.CloudResourceID},
Protocol: aws.Int(6),
}, NpNamespacedName: testAnpNamespacedName.String(),
Expand Down
Loading

0 comments on commit df221b8

Please sign in to comment.